简体   繁体   中英

React Native Run Child Reference Method From Another Component

I am trying to run a component method of another component. I am trying this using react ref. I am also following this link: https://medium.freecodecamp.org/react-changing-state-of-child-component-from-parent-8ab547436271 But my structure is a bit more complicated.

List.js

class List extends Component {

    constructor(){
        super()
        this.LoadCounterElement = React.createRef()
    }

    render(){
        return(
            <View>
                <ItemGenerator />
                <LoadCounter ref={this.LoadCounterElement}/>
            </View>
        )
    }
}

function mapStateToProps(state) {
    return {
        counter: state.counter.counter
    }
}

function mapDispatchToProps(dispatch) {
    return {
        increaseCounter: () => dispatch({ type: 'INCREASE_COUNTER' }),
        decreaseCounter: () => dispatch({ type: 'DECREASE_COUNTER' }),
    }
}

export default connect(mapStateToProps)(List);

ItemGenerator.js

class ItemGenerator extends Component {

    render() {
        return (
            <ScrollView>
                {
                    this.state.data.map((item, index) => {
                        return(<ItemList navigate={this.props.navigate} data={item} key={index}/>)
                    })
                }
            </ScrollView>
        )
    }

}

LoadCounter.js

class LoadCounter extends Component {

    constructor(props) {
        super(props)
        this.state = {
            count : 0,
        }
    }

    componentDidMount() {
        this._renderCount()
    }

    _renderCount = () => {
        this.setState({count:this.props.counter})
    }

    render(){
        return(
            <View>
                <Text>{this.state.count}</Text>
            </View>
        )
    }
}

function mapStateToProps(state) {
    return {
        counter: state.counter.counter
    }
}

export default connect(mapStateToProps)(withNavigation(LoadCounter));

ItemList.js

class ItemList extends Component {
    render() {
        return(
            <View>
                <TouchableOpacity onPress={() => {
                    this.props.increaseCounter()
                    this.LoadCounterElement.current._renderCount()
                }}>
                    <Card containerStyle={{margin: 0}}>
                        <View style={{flex:1, flexDirection:'row', height:70, alignItems:'center', justifyContent:'space-between'}}>
                            <View style={{flexDirection:'row', alignItems:'center', width:'55%'}}>
                                <View style={{flexDirection:'column', marginLeft:10}}>
                                    <Text style={{...}}>{this.props.data.name}</Text>
                                </View>
                            </View>
                        </View>
                    </Card>
                </TouchableOpacity>
            </View>
        )
    }
}

function mapDispatchToProps(dispatch) {
    return {
        increaseCounter: () => dispatch({ type: 'INCREASE_COUNTER' }),
        decreaseCounter: () => dispatch({ type: 'DECREASE_COUNTER' }),
    }
}

export default connect(mapStateToProps)(ItemList);

counterReducer.js

const initialState = {
    counter: 1
}
const counterReducer = (state = initialState, action) => {
    switch (action.type) {
        case 'INCREASE_COUNTER':
            return { counter: state.counter + 1 }
        case 'DECREASE_COUNTER':
            return { counter: state.counter - 1 }
    }
    return state
}

export default counterReducer;

As you can see in ItemLiist Component, i am trying to run _renderCount method which is in Component LoadCounter. But its not working. Kindly guide what i am missing?

The problem here is that you have some data in child component that should be reflected in a parent component. I would recommend that you move the shared state in the parent component or to the reducer state.

It is odd that you are using an action creator to increment/decrement counts - which I am thinking that updates some reducer state. If this is the case, why store that state in the local component state again ? You could just read the counter state from the reducer in your parent component.

Parent.js

class Parent extends React.Component {
  render() {
    return (
      <div>
        <span>{this.props.count}</span>
      </div>
    );
  }
}

const mapStateToProps = state => ({
  count: state.yourCountReducer.count,
});

export default connect(mapStateToProps)(Parent);

Child.js

class Child extends React.Component {
  render() {
    return (
      <div>
        <button onClick={() => this.props.increaseCounter()}>+</button>
        <button onClick={() => this.props.decreaseCounter()}>-</button>
      </div>
    );
  }
}

const mapDispatchToProps = dispatch => ({
  increaseCounter: () => dispatch({ type: 'INCREASE_COUNTER' }),
  decreaseCounter: () => dispatch({ type: 'DECREASE_COUNTER' }),
});

export default connect(null, mapDispatchToProps)(Child);

This way, the parent component will show the updated counter state when the child component updates the count. From your sample code, I am not sure if there is any good reason to store a shared reducer state in any component's local state.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM