Каков наилучший способ обновить объект в состоянии использования и немедленно увидеть изменения

#reactjs #react-native #react-hooks #jsx #use-state

Вопрос:

 const TestScreen = (props) => {

    const [data, setData] = useState([ 
            { "id": "0", "user": "Lisa","amount": 1 },
        ]);

        return(
            <View style={{
                            flex:1, 
                            alignItems:'center',
                            justifyContent:'center'
                        }}>
            <Text>amount : {data[0].amount}</Text>
            <Text>User : {data[0].user}</Text>
            <Button title="update" onPress={()=>setData(??????)}></Button>
          </View>
           
        )
    }
  
  export default TestScreen;
 

каков наилучший способ добавить номер суммы на имя пользователя? я могу сделать
// setData([{ «идентификатор»: «0», «пользователь»: «Лиза»,»сумма»: данные[0].сумма 1}])
но что у меня 5 пользователей или 20?

даже с возвращаемой функцией ничего не обновляется, кроме ведьмы, зарегистрированной в консоли, покажите мне фактическое значение

    let countAddFunc =(getArr)=>{
          let arr = getArr
          arr[0].amount  
          console.log(arr[0].amount);
          return(
            arr
          )
        }

<Button title="update" onPress={()=>setData(countAddFunc(data))}></Button>
 

Ответ №1:

Одна из ключевых концепций в React-Не изменять состояние напрямую. Иногда это может быть сложно, особенно при работе с вложенными данными, как в вашем примере (a number как свойство объекта внутри массива).

Ниже я переработал ваш код и добавил комментарии, чтобы помочь объяснить. Создав функцию для обновления состояния и передав эту функцию реквизитам каждого дочернего компонента, дочерний компонент сможет обновить состояние, вызвав функцию.

 const {useState} = React;

// component dedicated to displaying each item in the array
const Item = (props) => (
  <div style={{
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  }}>
    <div>Amount: {props.item.amount}</div>
    <div>User: {props.item.user}</div>
    <button onClick={() => {
      props.updateAmount(props.item.user);
    }}>Increment</button>
  </div>
);

const ItemList = () => {
  const [data, setData] = useState([
    {
      id: '0',
      user: 'Lisa',
      amount: 1,
    },
    {
      id: '1',
      user: 'Walter',
      amount: 3,
    },
  ]);

  const updateAmount = (user, changeAmount = 1) => {
    // find the index of the item we want
    const index = data.findIndex(item => item.user === user);

    // return early (do nothing) if it doesn't exist
    if (index === -1) return;

    const item = data[index];

    // don't modify state directly (item is still the same object in the state array)
    const updatedItem = {
      ...item,
      amount: item.amount   changeAmount,
    };

    // again, don't modify state directly: create new array
    const updatedArray = [...data];

    // insert updated item at the appropriate index
    updatedArray[index] = updatedItem;

    setData(updatedArray);
  };

  return (
    <ul>
      {data.map(item => (
        <li key={item.id}>
          <Item item={item} updateAmount={updateAmount} />
        </li>
      ))}
    </ul>
  );
};

ReactDOM.render(<ItemList />, document.getElementById('root')); 
 <script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js"></script>

<div id="root"></div> 

Ответ №2:

можете ли вы попробовать так один раз, передать второй параметр в качестве идентификатора пользователя, который вы хотите обновить

 <Button title="update" onPress={()=>setData(countAddFunc(data, 0))}></Button> 
 let countAddFunc =(getArr, id)=>{
          const arrCopy = [...getArr]
          const user = arrCopy.find(u => u.id === id )
          if (user) {
             user.amount  
          }
          return arrCopy
        } 

на самом деле вы непосредственно изменяете состояние, и мы не можем напрямую обновлять состояние, и getArr-это просто рефрен к данным в состоянии, поэтому мы создали копию массива и изменили скопированный массив, а затем ввели этот новый массив в состояние, о том, что код выдает неопределенную ошибку, добавьте проверку, если (пользователь) user.amount и убедитесь, что идентификатор, который вы отправляете onPress={()=>setData(countAddFunc(данные, 0))} действительно существует

Комментарии:

1. Я попробовал ваш код, и я получаю undefined is not an object(evaluating 'user.amount')

2. При добавлении […getArr] в функцию countAddFunc() выполняйте свою работу… это почему?

3. на самом деле вы напрямую изменяли состояние, и мы не можем напрямую обновлять состояние, getArr-это просто ссылка на данные в состоянии, поэтому мы создали копию массива и изменили скопированный массив, а затем установили этот новый массив в состояние, о том, что код выдает неопределенную ошибку, добавьте проверку, если (пользователь) user.amount и убедитесь, что идентификатор, который вы отправляете onPress={()=>setData(countAddFunc(данные, 0))} действительно существует

Ответ №3:

Подумайте о setState() как о запросе, а не о немедленной команде для обновления компонента. Для повышения воспринимаемой производительности React может задержать ее, а затем обновить несколько компонентов за один проход. React не гарантирует, что изменения состояния будут применены немедленно. Функция setState() не всегда сразу обновляет компонент. Он может выполнить пакетное обновление или отложить его на более поздний срок. Это делает чтение this.state сразу после вызова setState() потенциальной ловушкой.

Прочтите официальную документацию для получения дополнительной информации здесь

Кроме того, в качестве альтернативы вы можете использовать useRef или useEffect с массивом зависимостей, если хотите, чтобы обратный вызов немедленно сработал и внес изменения.

Комментарии:

1. я попытался добавить эффект использования, он ничего не отключает useEffect(() => { console.log("Logged out"); },[data]);

2. Но при добавлении […getArr] выполняйте свою работу и распечатывайте в useEffect «Вышел из системы», почему это так? какая разница, если добавить […getArr], а затем просто getArr let countAddFunc =(getArr)=>{ let arr = [...getArr] arr[0].amount setData(arr) }