简体   繁体   English

如何从 React Native 中的另一个 class 组件设置状态?

[英]How to setState from another class component in React Native?

I have a problem.我有个问题。 I want after I successfully add product to cart my shopping cart badge will be updated.我希望在成功将产品添加到购物车后,我的购物车徽章将被更新。 But I can't setState the itemCart component.但我不能 setState itemCart 组件。 This is code when i add products in cart.这是我在购物车中添加产品时的代码。 Function _datmon() will do that. Function _datmon() 会这样做。

import React, { Component } from 'react';
import {View,Text,StyleSheet,Dimensions,Image, TouchableOpacity,Modal, Button, Alert} from 'react-native';
import { RecyclerListView, DataProvider, LayoutProvider } from "recyclerlistview";
import { Snackbar} from 'react-native-paper';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import AsyncStorage from '@react-native-community/async-storage';
import Home from '../Home';
import 'regenerator-runtime/runtime';
export default class FoodByList extends Component{
   
    constructor(props){
        super(props);
        this.state={
            mang:[],
            dataProvider: new DataProvider ((r1,r2)=> r1!==r2),
            statusInform:false,
            modalVisible: false,
            id:'',
            gia:'',
            mota:'',
            soluong:1,
            mangmonan:[{
                id:'',
                soluong:'',
            }],
            getArr:[],
            hide: true,
        }
        this.home = new Home();
        this.homeref = React.createRef();
    }
   
    openModalWithItem(item) {
        this.setState({
            ten: item.ten,
            gia: item.gia,
            hinhanh: item.hinhanh,  
            id: item.id,
            mota: item.mota,
        })
    }
   
    layoutProvider = new LayoutProvider(
        index => {
            return index;
        }, 
        (type,dim) => {
        dim.width = Dimensions.get('window').width/2;
        dim.height = 280;
        }
    ) 
 
    _datmon = async()=>{
      
        //Get array availible device
        try {
            const myArray = await AsyncStorage.getItem('keyOrdermonan');
            if (myArray !== null) {
              // We have data!!
              console.log(JSON.parse(myArray));
            }
          } catch (error) {
            // Error retrieving data
            console.log(error);
        }
        const myArray = await AsyncStorage.getItem('keyOrdermonan');
        if(myArray !=null){
            this.state.getArr = JSON.parse(myArray);
            //Id food currently 
            const check = {id:this.state.id};
            var position = 0;
            //Check id avalilabled in cart ? 
            const police = this.state.getArr.some(getA => getA.id===check.id );
            
            if(police==true){
                for(var i =0;i<this.state.getArr.length;i++){
                    if(this.state.getArr[i].id==this.state.id){
                        break;
                    }else{
                    position+=1;
                    }
                }
                this.state.getArr[position].soluong += this.state.soluong;
                this.setState({mangmonan: this.state.getArr});
                this.homeref.setSizeCart(this.state.mangmonan.length);
                console.log('Completely udrage quanity');
            }
            else if(police==false){
                this.setState({mangmonan: [{id: this.state.id, 
                                            soluong: this.state.soluong,
                                    }].concat(this.state.getArr)});
                this.homeref.setSizeCart(this.state.mangmonan.length);
                                    
            }
        }else{
            this.setState({mangmonan: [{id: this.state.id, 
                                        soluong: this.state.soluong,
                                    }]});
            this.homeref.setSizeCart(this.state.mangmonan.length);
           
        }
        
        // Add new cart
        try {
            await AsyncStorage.setItem('keyOrdermonan', JSON.stringify(this.state.mangmonan));
            // await AsyncStorage.removeItem('keyOrdermonan');
            this.setState({modalVisible:false,soluong:1});
            Alert.alert(
                "Thành công",
                "Đặt món thành công, vui lòng kiểm tra giỏ hàng",
                [
                   
                    {
                        text: "Kiểm tra giỏ hàng",
                        onPress: ()=>{this.props.navigation.navigate('cart')}
                    },
                    {
                        text: "Tiếp tục đặt món",
                        style:'cancel'
                    },
                ]
                
            );
          } catch (error) {
            // Error saving data
            console.log(error);
        }

     
    }
    getPriceVND = (giatri) => {
        const parts = giatri.toString().split(".");
        parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
        const gia = parts.join(".");
        return gia;
    }

    rowrender = (type,item) => {
        
        return(
        <View style={styles.bgitem}>
            <TouchableOpacity style={styles.wrapperitem} onPress={()=> {this.setState({modalVisible:true}),this.openModalWithItem(item)}}>
            <View style={styles.wrapperimg}>
            <Image source={{ uri: item.hinhanh }} style={styles.img}/>
            </View>
            </TouchableOpacity>

            <View style={styles.wrappername}>
            <Text style={{ fontWeight:'bold' }}>Tên món ăn:</Text>
            <Text style={styles.under}>{item.ten}</Text>
            </View>

            <View style={styles.wrappername}>
            <Text style={{ fontWeight:'bold' }}>Giá: </Text>
            <Text style={styles.under}>{this.getPriceVND(item.gia)}đ</Text>
            </View>
        </View>
        
        )
        
    }
    componentDidMount(){
        //set lại tittle bar
        this.props.navigation.setOptions({title:this.props.route.params.tendanhmuc});

        fetch("http://192.168.43.25/DemoJWT/getMonAnByList.php",{
            method:'POST',
            headers: {
                "Accept":"application/json",
                "Content-Type":"application/json"
                },
            body: JSON.stringify({
                "IDDANHMUC" : this.props.route.params.id,
             })
        })
        .then((reponse)=>reponse.json())
        .then((reponseJson)=>{
            
           if(reponseJson==""){
               this.setState({statusInform:true});
           }else{
            this.setState({
                mang:reponseJson,
                dataProvider:this.state.dataProvider.cloneWithRows(reponseJson),
            })
           }
        })
        .catch((err)=>{
            console.log(err);
        })

    }
    render(){
        return(
            
            <View style={styles.wrapper}>
                {!this.state.hide &&  <Home ref={this.homeref} />}
               
                { !this.state.dataProvider.getSize()==0 &&
                <RecyclerListView
                    layoutProvider={this.layoutProvider}
                    rowRenderer={this.rowrender}
                    dataProvider = {this.state.dataProvider}
                />
                }

            {/* Thông báo khi không có món */}
            <Snackbar
                visible={this.state.statusInform}
                onDismiss={()=>{this}}
                action={{
                label: 'Trở về',
                onPress: () => {
                this.props.navigation.goBack()
              },
                }}>
               Hiện nhà hàng chưa có các món ăn này.
               Mong quý khách thông cảm !
            </Snackbar>
            {/* Thông báo khi không có món */}

            {/* Hiển thị khi nhấn chi tiết món ăn để đặt hàng */}
            <View>
                <Modal
                    animationType="slide" 
                    transparent={true}
                    visible={this.state.modalVisible}
                 >
                <View style={styles.modalView}>
                
                <View style={styles.wrapperimgModal}>
                    <Image source={{ uri: this.state.hinhanh }} style={styles.imgModal}/>
                
                    <View style={styles.wrappername,{marginTop:15}}>
                        <Text style={{ fontWeight:'bold',fontSize:18, }}>Tên món ăn:</Text>
                        <Text >{this.state.ten}</Text>
                    </View>

                    <View style={{ flexDirection:'column' }}>
                        <Text style={{ fontWeight:'bold',fontSize:18, }}>Giá: </Text>
                        <Text>{this.getPriceVND(this.state.gia)} đ / 1 phần</Text>
                    </View>

                    <View style={styles.wrappername}>
                        <Text style={{ fontWeight:'bold',fontSize:18, }}>Mô tả:</Text>
                        <Text>{this.state.mota}</Text>
                    </View>
                    <View style={styles.wrappername}>
                        <Text style={{ fontWeight:'bold',fontSize:18, }}>Số lượng:</Text>
                        <View style={{ flexDirection:'row',marginLeft:0,marginTop:10 }}>
                            <TouchableOpacity style={styles.decrease} onPress={()=>{
                                if(this.state.soluong==1){
                                    console.log('Không giảm nữa');
                                }else{
                                    this.setState({soluong:this.state.soluong-1})
                                }
                                }}>
                            <MaterialCommunityIcons name='minus-circle' color="black" size={24} />
                            </TouchableOpacity>
                            <Text>{this.state.soluong}</Text>
                            <TouchableOpacity style={styles.increase} onPress={()=>{
                                if(this.state.soluong==15){
                                    console.log('Không tăng nữa');
                                }
                                else{
                                    this.setState({soluong:this.state.soluong+1})
                                }
                                }}>
                            <MaterialCommunityIcons name='plus-circle' color="black" size={24} />
                            </TouchableOpacity>
                        </View>
                    </View>
                </View>
                
                <View style={styles.totalbtn}>
                    <View style={styles.btn}>
                    <Button 
                        title="Hủy"
                        onPress={()=>{this.setState({modalVisible:false,soluong:1})}}
                    />
                    </View>
                    <View style={styles.btn2}>
                    <Button title="Đặt ngay"
                        onPress={()=>{this._datmon()}}
                    />
                    </View>
                </View>

                </View>
            </Modal>
            </View>
            {/* Hiển thị khi nhấn chi tiết món ăn để đặt hàng */}   


            </View>
        )
    }
}
const styles = StyleSheet.create({

    wrapper:{
        flex:1,
        
    },
    wrapperitem:{
        flex:1,

    },
    title:{
        fontSize:30,
        padding:10,
        fontWeight:'bold',
    },
    bgitem:{
        flex:1,
        flexDirection:'column',
        padding:10,
        margin:10, 
        borderWidth:1,
        borderRadius:15,
        backgroundColor:'#dddddd',

    },
    wrapperimg:{
        width:"100%",
        height:180,
        alignItems:'center',
        padding:5,
    },
    wrapperimgModal:{
        width:"100%",
        height:370,
        padding:5,
        marginLeft:10,
    },
    img:{
        width:'80%',
        height:100,
        borderRadius:10,
    },
    imgModal:{
        width:'100%',
        height:150,
        borderRadius:10,
    },
    wrappername:{
        flexDirection:'column',
    },
    under:{
        paddingLeft:10,
    },
    
    modalView: {
        margin: 20,
        marginTop:100,
        backgroundColor: "white",
        borderRadius: 20,
        padding: 35,
        shadowColor: "#000",
        shadowOffset: {
          width: 0,
          height: 2
        },
        shadowOpacity: 0.25,
        shadowRadius: 4,
        elevation: 5
      },
    totalbtn:{
        flexDirection:'row',
        alignItems:'center',
        justifyContent:'center'
    },
    btn:{
        width:90,
        marginRight:10,
      },
    btn2:{
        width:90,
        marginLeft:10,
    },
    decrease:{
        marginRight:10,
    },
    increase:{
        marginLeft:10
    }
})

Still here is your code setSizeCart() in class component Home.js:仍然是 class 组件 Home.js 中的代码 setSizeCart():

import React, { Component } from "react";
import {StyleSheet, Alert,View, StatusBar,Linking, Text} from "react-native"
import AsyncStorage from '@react-native-community/async-storage';
import HomeScreen from "./Screen/HomeScreen";
import FavouriteScreen from "./Screen/FavouriteScreen";
import ProfileScreen from "./Screen/ProfileScreen";
import CartScreen from "./Screen/CartScreen";
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import { Appbar, Snackbar,Badge } from 'react-native-paper';
import NetInfo from "@react-native-community/netinfo";
import {createDrawerNavigator} from "@react-navigation/drawer"
import { DrawerActions } from '@react-navigation/native';
import SettingScreen from "./Screen/SettingScreen";
import BookingScreen from "./Screen/BookingScreen";
import FullFood from "./Screen/FullFood";
import 'regenerator-runtime/runtime';

const Drawer = createDrawerNavigator();


export default class Home extends Component{
    
    _isMounted = false;
    constructor(props){
        super(props);
        this.state={
            token:"",
            ten:"",
            statusInform:false,
            searchQuery:"",
            getMangAsync:[],
            itemcart: 0 ,   
        }
        this.setSizeCart = this.setSizeCart.bind(this);
    }
    setSizeCart (bien){
        try {
            this.setState({ itemcart: bien });
            console.log("set thành công");
        } catch (error) {
            console.log(error);
        }   
    }
    _getasyc = async()=>{
        try {
            const key = await AsyncStorage.getItem("keyOrdermonan");
            if(key!==null){
                this.setState({getMangAsync:JSON.parse(key)});
                this.setState({itemcart:this.state.getMangAsync.length});
            }
         } catch (error) {
             console.log(error)
        }    
    }
    checkInternet(){
        NetInfo.fetch("http://192.168.43.25/DemoJWT/checkToken.php")
        .then(state=>{
            console.log(state.isConnected)
            if(state.isConnected==false){
                this.setState({statusInform:true})
            }
        })
    }

    componentDidMount(){
        this._isMounted = true;
        if(this._isMounted){
            this.checkInternet();
            this._getasyc();
        }
    }
    componentWillUnmount(){
        this._getasyc();
        // console.log("đã"+ this._isMounted)
    }   
    

    _logout = async() =>{
        try {
            await AsyncStorage.removeItem("keyToken");
            Alert.alert("Đăng xuất");
            this.props.navigation.navigate('login');
            
        } catch (error) {
            console.log(error)
        }
    }
    contact(){
        Alert.alert(
            "Liên hệ với chúng tôi",
            "Bạn có muốn hay không?",
            [
                {
                    text: "Hủy",
                    style:'cancel'
                },
                {
                    text: "Đồng ý",
                    onPress: ()=>Linking.openURL('tel:$+84705982473')
                }
            ]

        )
    }
    
render(){
    //    const {ten} = this.props.route.params
        return(
            <View style={{ flex:1 }}>
                <StatusBar backgroundColor='#555555' barStyle="light-content" />
                <Appbar style={styles.appbar}>
                    <Appbar.Action icon="format-list-bulleted" onPress={()=>(this.props.navigation.dispatch(DrawerActions.openDrawer()))}/>
                    <Appbar.Content title="GREAT FOOD" />
                    <Badge  
                        visible={this.state.itemcart && this.state.itemcart >0}
                        size={17}
                        style={{ position: 'absolute', top: 5, right: 55 }}>{this.state.itemcart}</Badge>
                    <Appbar.Action icon="cart" onPress={()=>{this.props.navigation.navigate('cart')}}/>
                    <Appbar.Action icon="phone-in-talk" onPress={()=>{this.contact()}}/>
                </Appbar>
                
                <Drawer.Navigator 
                    overlayColor="transparent"   
                > 
                    <Drawer.Screen name ="home" component={HomeScreen} 
                        options={{
                            drawerLabel:"Menu",
                            drawerIcon:({color})=>(
                                <MaterialCommunityIcons name="home" color={color} size={26} />
                        ), }}
                        />
                    <Drawer.Screen name="profile" component={ProfileScreen}
                            options={{
                            drawerLabel:"Hồ sơ",
                            drawerIcon:({color})=>(
                                <MaterialCommunityIcons name="account-circle" color={color} size={26} />
                        ), }}
                    />
                    <Drawer.Screen name="fullfood" component={FullFood}
                        options={{
                            drawerLabel:"Tất cả món ăn",
                            drawerIcon:({color})=>(
                                <MaterialCommunityIcons name="food" color={color} size={26} />
                        ), }}
                    />
                    <Drawer.Screen name= "favourite" component={FavouriteScreen}
                        options={{    
                            drawerLabel:"Yêu thích",
                            drawerIcon:({color})=>(
                                <MaterialCommunityIcons name="heart-pulse" color={color} size={26} />
                        ), }}
                    />
                     <Drawer.Screen name= "booking" component={BookingScreen}
                        options={{
                            drawerLabel:"Đặt bàn",
                            drawerIcon:({color})=>(
                                <MaterialCommunityIcons name="table-furniture" color={color} size={26} />
                        ), }}
                    />
                    <Drawer.Screen name="cart" component={CartScreen}
                        options={{
                            drawerLabel:"Giỏ hàng",
                            drawerIcon:({color})=>(
                                <MaterialCommunityIcons name="cart" color={color} size={26} />
                        ), }}
                    />
                    <Drawer.Screen name="setting" component={SettingScreen}
                        options={{
                            drawerLabel:"Cài đặt",
                            drawerIcon:({color})=>(
                                <MaterialCommunityIcons name="wrench-outline" color={color} size={26} />
                        ), }}
                    />
                </Drawer.Navigator>
             <Snackbar
                visible={this.state.statusInform}
                onDismiss={()=>{this}}
                action={{
                label: 'Tắt',
                onPress: () => {
                this.setState({statusInform:false})
              },
             }}>
            Vui lòng kiểm tra kết nối.
            </Snackbar>
        </View>
        )
    }
}
const styles = StyleSheet.create({
    wrapper:{
        flex:1,
        justifyContent:"center",
        alignItems:'center',
    },
    logout:{
        marginTop:50,
    },
    appbar:{
        backgroundColor:'#555555' 
    },

})

And I have been received warning is:我收到的警告是:

Can't call setState on a component that is not yet mounted.无法在尚未安装的组件上调用 setState。 This is a no-op, but it might indicate a bug in your application.这是一个无操作,但它可能表明您的应用程序中存在错误。 Instead, assign to this.state directly or define a state = {};相反,直接分配给 this.state 或定义一个 state = {}; class property with the desired state in the Home component. class 属性在 Home 组件中具有所需的 state。

Can anyone help me!谁能帮我!

So one small thing you are missing here is that,所以你在这里缺少的一件小事是,

Creating a new component using the new keyword is not going to mount that component into the render tree.使用new关键字创建新组件不会将该组件安装到渲染树中。

You should include it inside the render function of your FoodByList like this您应该像这样将它包含在FoodByListrender function 中

<Home ref={this.homeRef} />

Then, in the constructor of your FoodByList component, create the homeRef using然后,在FoodByList组件的constructor homeRef ,使用

this.homeRef = React.createRef();

More on React.createRef in this article .更多关于React.createRef在这篇文章中

Basically assigning a ref to the Home component inside the render of FoodByList gives you the ability to call the functions inside the Home component.基本上,在FoodByListrender中将 ref 分配给Home组件使您能够调用Home组件内的函数。

Next, in Home component's constructor use this.setSizeCart = this. setSizeCart.bind(this)接下来,在Home组件的构造函数中使用this.setSizeCart = this. setSizeCart.bind(this) this.setSizeCart = this. setSizeCart.bind(this) or else convert the setSizeCart function into an arrow function like this this.setSizeCart = this. setSizeCart.bind(this)或者像这样将setSizeCart function 转换为箭头 function

setSizeCart = (bien) => {
    try {
        this.setState({ itemcart: bien });
        console.log("set successfully");
    } catch (error) {
        console.log(error);
    }
}

So now, instead of doing this.home.setSizeCart(this.state.mangmonan.length) you should be doing this.homeRef.current.setSizeCart(this.state.mangmonan.length)所以现在,而不是这样做this.home.setSizeCart(this.state.mangmonan.length)你应该这样做this.homeRef.current.setSizeCart(this.state.mangmonan.length)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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