繁体   English   中英

我正在从另一个组件更改 REACT 组件的 state 但没有刷新

[英]I am changing the state of the REACT component from another component but no refresh

我需要一盏灯看看缺少什么? 当我将用户添加到后端时,我正在更改 Users REACT 组件的 state。 用户添加没有问题。 我发送了 User 元素的 state,当“onSubmit:”发生但 Users REACT 组件没有重新加载时,我更改了 state。 这种方法有什么问题?

import { v4 as uuidv4 } from 'uuid';
import React, { useState, useEffect }  from 'react';
import { useFormik } from 'formik';
function unique_id() {
    return uuidv4()
}
var PlayersBackend='/players';
const validate = values => {
    const errors = {};
    if (values.firstName === 0 || values.firstName.replace(/^\s+|\s+$/gm, '').length === 0) {
        errors.firstName = 'Required';
    } else if (values.firstName.length === 0) {
        errors.firstName = 'The message must be no empty';
    }

    if (values.lastName === 0 || values.lastName.replace(/^\s+|\s+$/gm, '').length === 0) {
        errors.lastName = 'Required';
    } else if (values.lastName.length === 0) {

        errors.lastName = 'The message must be no empty';
    }
    return errors;
};
const addPlayer = async (firstName, lastName) => {
    await fetch(PlayersBackend, {
        method: 'POST',
        mode: 'cors',
        cache: 'no-cache',
        credentials: 'same-origin',
        headers: {
            "Content-Type":"application/json",
        },
        body: JSON.stringify({ firstName, lastName })
    })

};


const AddPlayerForm=(compUsersState) =>{
    const formik = useFormik(
        {initialValues:{firstName: '',lastName: '',},
            validate,
            onSubmit: (values,{resetForm}) =>
        {  addPlayer(values.firstName,values.lastName).then();
            resetForm();
            console.log(compUsersState.compUsersState)
            compUsersState.compUsersState(p => p+1);

        },
    });
    return (
        <form onSubmit={formik.handleSubmit}>
            <label htmlFor="firstName">First Name</label>
            <input
                id="firstName"
                name="firstName"
                type="text"
                onChange={formik.handleChange}
                value={formik.values.firstName}
            />
            <label htmlFor="lastName">Last Name</label>
            <input
                id="lastName"
                name="lastName"
                type="text"
                onChange={formik.handleChange}
                value={formik.values.lastName}
            />

            <button type="submit">Add user</button>
        </form>
    );
};

export const Users = () => {

    const [error, setError] = useState(null);
    const [isLoaded, setIsLoaded] = useState(false);
    const [users, setPlayers] = useState([]);
    const [,compUsersState] = useState(0);
    useEffect(() => {
        fetch(PlayersBackend).then(response => response.json()).then((data) => { setIsLoaded(true);setPlayers(data);}, (error) => {setIsLoaded(true);setError(error);})},[])
    if (error) {
        return <div>Error: {error.message}</div>;
    } else if (!isLoaded) {
        return <div>Loading...</div>;
    } else {

        if (typeof (users._embedded) !== 'undefined')
        {
            return (

                <ul>
                    <AddPlayerForm compUsersState={compUsersState}/>
                    {users._embedded.players.map(player => (
                        <li className="d-flex justify-content-start" key={unique_id()}>
                            {player.firstName} {player.lastName}
                        </li>
                    ))}

                </ul>
            );

        }
        else return  (<ul> </ul> )

    }

}

这可能是由于 useEffect 它只在加载组件时执行一次,将用户添加到 useEffect 依赖项可能会有所帮助

 useEffect(() => {
    fetch(PlayersBackend)
      .then((response) => response.json())
      .then(
        (data) => {
          setIsLoaded(true);
          setPlayers(data);
        },
        (error) => {
          setIsLoaded(true);
          setError(error);
        }
      );
  }, [users,users.length]);

更新:看到useEffect的回答后,让我想到了一个实现刷新的新思路。

Users中,

const [refreshCounter, compUsersState] = useState(0);


useEffect(() => {
    fetch(PlayersBackend)
      .then((response) => response.json())
      .then(
        (data) => {
          setIsLoaded(true);
          setPlayers(data);
        },
        (error) => {
          setIsLoaded(true);
          setError(error);
        }
      );
  }, [refreshCounter]);

通过将计数器 state 添加到依赖项数组中,您可以确保每次计数器递增时都会触发useEffect


我建议将setPlayers function 传递给<AddPlayerForm> ,并在成功添加玩家后触发 function 将新玩家添加到users列表中。

Users中,

<AddPlayerForm compUsersState={compUsersState} setPlayers={setPlayers} />

AddPlayerForm中,

const AddPlayerForm = ({compUsersState, setPlayers}) => {
  const formik = useFormik({
    initialValues: { firstName: "", lastName: "" },
    validate,
    onSubmit: (values, { resetForm }) => {
      addPlayer(values.firstName, values.lastName).then();
      resetForm();
      console.log(compUsersState.compUsersState);
      compUsersState.compUsersState((p) => p + 1);
      const newPlayer = values; // Or change the format
      setPlayers((p) => [...p, newPlayer])
    },
  });
  ...

我可以看到您正在尝试通过调用compUsersState((p) => p + 1)来刷新Users组件,我认为它正在运行。 如果不确定,请使用 React Developer Tool 检查元素并检查 state 是否已成功更改。

但实际问题是users state 没有得到更新。 所以用户界面看起来和以前一样。

尝试使用forceupdate类的

const forceUpdate = React.useReducer(bool => !bool)[1];

并致电 state 更新

forceUpdate();

我的最终解决方案是使用 axios。我将 state 作为参数发送
<AddPlayerForm useState={[listPlayers, setPlayers]}/>

当我添加一个用户时,我打电话

let temp_listPlayers=[...listPlayers,response.data]
setPlayers(temp_listPlayers);

这是供您参考的完整代码。

import { v4 as uuidv4 } from 'uuid';
import React, { useState, useEffect }  from 'react';
import axios from 'axios';
import { useFormik } from 'formik';
// PlayersBackend must be change in Sync with the value in package.json 
// for now is set for the Backend and Frontend will be in the localhost 
//. "proxy": "http://localhost:8080", in package.json

var PlayersBackend='/players';
function unique_id() {
    return uuidv4()
}

const validate = values => {
    const errors = {};
    if (values.firstName === 0 || values.firstName.replace(/^\s+|\s+$/gm, '').length === 0) {
        errors.firstName = 'Required';
    } else if (values.firstName.length === 0) {
        errors.firstName = 'The message must be no empty';
    }
    if (values.lastName === 0 || values.lastName.replace(/^\s+|\s+$/gm, '').length === 0) {
        errors.lastName = 'Required';
    } else if (values.lastName.length === 0) {
        errors.lastName = 'The message must be no empty';
    }
    return errors;
};
function AddPlayer(firstName,lastName,useState) {
    const data = { firstName: firstName, lastName: lastName };
    let listPlayers=useState.useState[0];
    let setPlayers=useState.useState[1];
    axios.post(PlayersBackend, data)
        .then(response => {
            let temp_listPlayers=[...listPlayers,response.data]
            setPlayers(temp_listPlayers);
         }).catch(error => {
        console.error('Something went wrong!', error);
    });
;}

const AddPlayerForm=(useState) =>{
     const formik = useFormik(
        {initialValues:{firstName: '',lastName: '',},
            validate,
            onSubmit: (values,{resetForm}) =>
        {  AddPlayer(values.firstName,values.lastName,useState);
           resetForm();
        },
    });
    return (
        <form onSubmit={formik.handleSubmit}>
            <label htmlFor="firstName">First Name</label>
            <input
                id="firstName"
                name="firstName"
                type="text"
                onChange={formik.handleChange}
                value={formik.values.firstName}
            />
            <label htmlFor="lastName">Last Name</label>
            <input
                id="lastName"
                name="lastName"
                type="text"
                onChange={formik.handleChange}
                value={formik.values.lastName}
            />

            <button type="submit">Add user</button>
        </form>
    );
};

export const Users = () => {
   const [listPlayers, setPlayers] = useState({});
   const getPlayers = () =>
       axios.get(PlayersBackend)
           .then((response)=> {
               const myPlayers=response.data._embedded.players;
               setPlayers(myPlayers);
           })
        useEffect(()=>getPlayers(),[])
    if (typeof(listPlayers.length) !== 'undefined') {
         return (
            <ul>
                <AddPlayerForm useState={[listPlayers, setPlayers]}/>
                {listPlayers.map(player => (
                <li className="d-flex justify-content-start" key={unique_id()}>
                    {player.firstName} {player.lastName}
                </li>
                ))}
            </ul>
        );}
    return (
        <ul> </ul>
    );
}

暂无
暂无

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

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