-
Notifications
You must be signed in to change notification settings - Fork 320
nanachi的REF问题解决
司徒正美 edited this page Jan 15, 2019
·
1 revision
在小程序,由于页面组件不能直接引入业务组件,业务组件已经在index.json中通过usingComponents引入了。 这时nanachi通过useComponent解决了
比如说
import React from '@react';
import YButton from '@components/YButton/index';
import './index.scss';
class P extends React.Component {
constructor() {
super();
this.state = {
condition1: true,
condition2: true
};
}
toggleCondition2() {
this.setState({
condition2: !this.state.condition2
});
}
toggleCondition1() {
this.setState({
condition1: !this.state.condition1
});
}
componentDidMount(){
console.log(this.refs.aaa, 'componentDidMount');
}
render() {
return (
<div class='anu-block xxx'>
<div class='anu-block'>
<div>Condition1 active</div>
<YButton ref="aaa" id="ybutton" onTap={this.toggleCondition1.bind(this)}>
Inactive Condition1
</YButton>
<div>Condition2 active</div>
<YButton onTap={this.toggleCondition2.bind(this)}>
Inactive Condition2
</YButton>
</div>
</div>
);
}
}
export default P;
被编译成
import React from '../../../../ReactWX.js';
function P() {
this.state = {
condition1: true,
condition2: true
};
}
P = React.toClass(P, React.Component, {
toggleCondition2: function () {
this.setState({
condition2: !this.state.condition2
});
},
toggleCondition1: function () {
this.setState({
condition1: !this.state.condition1
});
},
componentDidMount: function () {
console.log(this.refs.aaa, 'componentDidMount');
},
render: function () {
var h = React.createElement;
return h('view', { 'class': 'anu-block xxx' },
h('view', { 'class': 'anu-block' }, h('view', null, 'Condition1 active'),
h(React.useComponent, { ref: 'aaa', id: 'ybutton', onTap: this.toggleCondition1.bind(this),
is: 'YButton', 'data-instance-uid': 'i34_20_' + 0 }, 'Inactive Condition1'),
h('view', null, 'Condition2 active'),
h(React.useComponent, { onTap: this.toggleCondition2.bind(this),
is: 'YButton', 'data-instance-uid': 'i38_20_' + 0 }, 'Inactive Condition2')));
},
classUid: 'c1315'
}, {});
Page(React.registerPage(P, 'pages/demo/syntax/if/index'));
export default P;
通过useComponent这个无状态组件进行引入。 但在无状态组件中不是能使用ref的,因此ref是无法传下去,并且中间多了一个组件,也会导致一部分的fiber的_owner出现错误。 解决办法有两个,1是将useComponent变成有状态组件
var useComponent = miniCreateClass(function useComponent(props) {
this.render = function(){
var fiber = get(this).return
while(fiber.return){
if(fiber.tag < 5){
get(this)._owner = fiber.stateNode;
// console.log(")))))",get(this), fiber.stateNode)
break
}
fiber = fiber.return
}
var props = this.props;
var is = props.is;
var clazz = registeredComponents[is];//解决import
props.key = props.key || props['data-instance-uid'] || new Date() - 0;//解决相邻同类型组件数据串了的问题
delete props.is;
if (this.ref !== null) {
props.ref = this.ref;
}
var args = [].slice.call(arguments, 2);
args.unshift(clazz, props);
return createElement.apply(null,args )
}
}, Component);
另一个是
function useComponent(props, context) {
var is = props.is;
var clazz = registeredComponents[is];
props.key = props.key || props['data-instance-uid'] || new Date() - 0;
delete props.is;
if (this.ref !== null) {
props.ref = this.ref;
}
var owner = Renderer.currentOwner;
if(owner){
Renderer.currentOwner = get(owner)._owner
}
return createElement(clazz, props);
}
``html
<script type='text/javascript' src="./dist/React.js"></script> <script type='text/javascript' src="./test/react.development.js"></script> <script type='text/javascript' src="./test/react-dom.development.js"></script><script type='text/javascript' src="./lib/babel.js"></script>
<pre>应该等于
</pre>
<h1 id='root' class="root">
</h1>
<script type='text/babel'>
var container = document.getElementById("example")
var div = container
var PropTypes = React.PropTypes
if(!window.ReactDOM){
window.ReactDOM = React
}
var expect = function(a) {
return {
toBe: function(b) {
console.log(a,"vs", b, a === b)
},
toEqual(b){
console.log(a,"vs", b, a +""=== b+"")
},
toThrow(b){
try{
a()
}catch(e){
console.log(e,"vs", b, e.message +""=== b+"")
}
}
}
}
const Hello = ({ name }) => <h1>Hello {name}!</h1>;
class ShowMyError extends React.Component {
constructor(props) {
super(props);
this.state = { error: false };
}
componentDidCatch(error, info) {
console.log(error, info)
this.setState({ error, info });
}
render() {
if (this.state.error) {
return (
<div>
<h1>
Error AGAIN: {this.state.error.toString()}
</h1>
{this.state.info &&
this.state.info.componentStack.split("\n").map(i => {
return (
<div key={i}>
{i}
</div>
);
})}
</div>
);
}
return this.props.children;
}
}
class Broken extends React.Component {
constructor(props) {
super(props);
this.state = { throw: false, count: 0 };
}
render() {
if (this.state.throw) {
throw new Error("YOLO");
}
return (
<div>
<button
onClick={e => {
this.setState({ throw: true });
}}
>
button will render error.
</button>
<button onClick={e => {
this.setState(({ count }) => ({
count: count + 1
}));
}}>button will not throw</button>
<div>
{"All good here. Count: "}{this.state.count}
</div>
</div>
);
}
}
class App extends React.Component {
render() {
const styles = {
fontFamily: "sans-serif",
textAlign: "center"
};
return (
<div style={styles}>
<Hello name="ShowMyError" />
<h2>
Start clicking to see some {"\u2728"}magic{"\u2728"}
</h2>
<ShowMyError>
<Broken />
</ShowMyError>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));