Реагировать крючки useState Array

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

Попытка изменить выпадающее значение из начального состояния в значения позволенного состояния. Я использую метод ловушек здесь, чтобы установить значения, используя - setStateValues. Если я прокомментирую эту строку кода, она отобразит раскрывающийся список. Я не мог понять, почему я не могу использовать метод setStateValues ​​для сброса значений переменных состояния.

Я получаю следующую ошибку: "Слишком много повторных визуализаций. React ограничивает количество визуализаций, чтобы предотвратить бесконечный цикл".

Пожалуйста, помогите, если вы видите здесь что-то не так. Я буду продолжать искать.

    import React, { useState } from "react"; 
    import ReactDOM from "react-dom";

    const StateSelector = () => {   
    const initialValue = [
    { id: 0,value: " --- Select a State ---" }];

      const allowedState = [
        { id: 1, value: "Alabama" },
        { id: 2, value: "Georgia" },
        { id: 3, value: "Tennessee" }
        ];

      const [stateOptions, setStateValues] = useState(initialValue);  
      // initialValue.push(...allowedState);

      console.log(initialValue.length);

      setStateValues(allowedState); // Not sure why cannot I reset the state in here for an array.

         return (<div>
          <label>Select a State:</label>
          <select>
            {stateOptions.map((localState, index) => (
              <option key={localState.id}>{localState.value}</option>
            ))}
          </select>
        </div>   ); };

    const rootElement = document.getElementById("root");
    ReactDOM.render(<StateSelector />, rootElement);

6 ответов

Решение

Вы не должны устанавливать состояние (или делать что-либо еще с побочными эффектами) из функции рендеринга. При использовании крючков вы можете использовать useEffect за это.

Следующая версия работает:

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

const StateSelector = () => {
  const initialValue = [
    { id: 0, value: " --- Select a State ---" }];

  const allowedState = [
    { id: 1, value: "Alabama" },
    { id: 2, value: "Georgia" },
    { id: 3, value: "Tennessee" }
  ];

  const [stateOptions, setStateValues] = useState(initialValue);
  // initialValue.push(...allowedState);

  console.log(initialValue.length);
  // ****** BEGINNING OF CHANGE ******
  useEffect(() => {
    // Should not ever set state during rendering, so do this in useEffect instead.
    setStateValues(allowedState);
  }, []);
  // ****** END OF CHANGE ******

  return (<div>
    <label>Select a State:</label>
    <select>
      {stateOptions.map((localState, index) => (
        <option key={localState.id}>{localState.value}</option>
      ))}
    </select>
  </div>);
};

const rootElement = document.getElementById("root");
ReactDOM.render(<StateSelector />, rootElement);

и вот оно в песочнице кода.

Я предполагаю, что вы хотите в конечном итоге загрузить список состояний из некоторого динамического источника (в противном случае вы могли бы просто использовать allowedState непосредственно без использования useState совсем). Если это так, то вызов API для загрузки списка также может идти внутри useEffect блок.

Постарайтесь, чтобы ваше состояние было минимальным. Нет необходимости хранить

   const initialValue = [
    { id: 0,value: " --- Select a State ---" }];

как состояние. Отделите перманент от изменения

const ALL_STATE_VALS = [
    { id: 0,value: " --- Select a State ---" }
    { id: 1, value: "Alabama" },
    { id: 2, value: "Georgia" },
    { id: 3, value: "Tennessee" }
];

Затем вы можете сохранить только идентификатор в качестве своего состояния:

const StateSelector = () =>{
  const [selectedStateOption, setselectedStateOption] = useState(0);

  return (
    <div>
      <label>Select a State:</label>
      <select>
        {ALL_STATE_VALS.map((option, index) => (
          <option key={option.id} selected={index===selectedStateOption}>{option.value}</option>
        ))}
      </select>
    </div>);
   )
}

Чтобы расширить ответ Райана:

Каждый раз, когда вызывается setStateValues, React повторно отображает ваш компонент, что означает, что тело функции StateSelector компонентная функция повторно выполняется.

Реагировать на документы:

setState() всегда будет приводить к повторной отрисовке, если shouldComponentUpdate() не вернет false.

По сути, вы устанавливаете состояние с помощью:

setStateValues(allowedState);

вызывает повторный рендеринг, который затем вызывает выполнение функции и так далее. Следовательно, проблема петли.

Чтобы проиллюстрировать это, если вы установите тайм-аут следующим образом:

  setTimeout(
    () => setStateValues(allowedState),
    1000
  )

На этом заканчивается проблема "слишком большого количества повторных рендеров".

В вашем случае вы имеете дело с побочным эффектом, который обрабатывается с помощью UseEffectв ваших компонентных функциях. Вы можете прочитать об этом здесь.

Принятый ответ показывает правильный способ setState, но не приводит к хорошо работающему окну выбора.

import React, { useState } from "react"; 
import ReactDOM from "react-dom";

const initialValue = { id: 0,value: " --- Select a State ---" };

const options = [
    { id: 1, value: "Alabama" },
    { id: 2, value: "Georgia" },
    { id: 3, value: "Tennessee" }
];

const StateSelector = () => {   
   const [ selected, setSelected ] = useState(initialValue);  

     return (
       <div>
          <label>Select a State:</label>
          <select value={selected}>
            {selected === initialValue && 
                <option disabled value={initialValue}>{initialValue.value}</option>}
            {options.map((localState, index) => (
               <option key={localState.id} value={localState}>
                   {localState.value}
               </option>
             ))}
          </select>
        </div>
      ); 
};

const rootElement = document.getElementById("root");
ReactDOM.render(<StateSelector />, rootElement);

Состояние использования не всегда необходимо, вы можете просто сделать это

let paymentList = [
    {"id":249,"txnid":"2","fname":"Rigoberto"}, {"id":249,"txnid":"33","fname":"manuel"},]

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

<div className="card-body">
            <div className="table-responsive">
                <table className="table table-striped">
                    <thead>
                        <tr>
                            <th>Transaction ID</th>
                            <th>Name</th>
                        </tr>
                    </thead>
                    <tbody>
                        {
                            paymentList.map((payment, key) => (
                                <tr key={key}>
                                    <td>{payment.txnid}</td>
                                    <td>{payment.fname}</td>
                                </tr>
                            ))
                        }
                    </tbody>
                </table>
            </div>
        </div>
      //get value
 const valor1 = event.target.elements.valor1.value;
//add to value object
        const todo = {
            valor1,
        }
//push to new value or your state
        setValor(prevLista =>{
            return prevLista.concat(todo)
        })
     
    }
Другие вопросы по тегам