2017-02-08 2 views
3

Я начинающий программист, пытающийся понять, как я должен иметь дело с состояниями внуков (или посмотреть, хорошо ли иметь внуки).React JS: Как установить состояния внуков

Мои вопросы ...

1. Можно ли изменить внукам через this.setState((prevState))?

2. Имеет ли внуки состояние плохой идеи?

Чтобы проиллюстрировать это, вот конструктор компонента.

constructor(props) { 
super(props); 
this.state = { 
    input: { 
    example: "", 
    }, 
    invalid:{ 
    example: false 
    }, 
}; 
this.handleChange = this.handleChange.bind(this); 
this.submit = this.submit.bind(this); 
} 

Я вижу this.state.invalid как ребенок, и this.state.invalid.example как внуку.

Это JSX.

<div className="input"> 
    <input type="text" value={this.state.input.example || ''} onChange={this.handleChange} /> 
    { this.state.invalid.example ? <span> This input is invalid </span> : null } 
</div> 
//Here are similar input fields... 

<button onClick={this.submit} type="button">Submit</button> 

Когда onClick={this.submit} обжигают, я хотел бы, чтобы подтвердить ввод данных в функции «this.submit».

submit(){ 
for (var key in this.state.input) { 
    if(!this.state.input[key]){ 
    this.setState((prevState, key) => ({ 
     invalid[key]:true, //This causes an error, saying that "SyntaxError: Unexpected token, expected ," 
    })); 
    } 
} 

В этом примере this.state.invalid.example предполагается установить (т.е. изменено), но выше код не работает.

Возможно, это будет лучшая идея разложить это приложение и сделать <div className="input"> одним компонентом. Прежде чем это сделать, я хотел бы уточнить, можно ли таким образом установить внуков.

Поскольку я не знаю никого вокруг меня, кто изучает ReactJS, любые советы будут оценены!

+1

Возможный дубликат: http://stackoverflow.com/questions/18933985/this-setstate-isnt-merging-states-as-i-would-expect – forrert

+0

Не совсем то, что я искал ... но это было очень информативный. Спасибо, что поделились ею! – Hiroki

ответ

3

Вы не можете передать состояние компонента предка компоненту-потомку по состоянию. Вы можете сделать это с помощью реквизита, но это приводит к передаче реквизита на многие уровни вниз. Есть также возможность с context, но это тоже нехорошо.

Лучший способ - использовать либо поток, либо редукцию. Я предпочитаю сокращение, а в сокращении вы можете получить переменные, которые ваш объект нуждается в одном магазине, используя метод connect.

https://github.com/reactjs/react-redux/blob/master/docs/api.md

проверка также these videos

+0

Извините за этот поздний ответ. Я пробовал много вещей, и теперь я чувствую, что Redux - лучшее решение для моего проекта. Благодаря! – Hiroki

2

Я не думаю, что это само по себе плохая идея, чтобы иметь вложенные состояния в компоненте. Важно помнить, однако, что setState

выполняет неглубокое слияние nextState в текущее состояние

см in the react documentation.

Так что, если ваше состояние является

{ 
    input: { 
    example: "asd", 
    other: "123" 
    }, 
    invalid: { 
    example: false, 
    other: false 
    } 
} 

и вы называете setState({invalid: {example: true}}), то результирующее состояние будет выглядеть

{ 
    input: { 
    example: "asd", 
    other: "123" 
    }, 
    invalid: { 
    example: true 
    } 
} 

Обратите внимание на все под invalid был заменен с новым состоянием, в то время как объект под input остался нетронутым (т.е. выполнено мелкое слияние).

В вашей submit функции, я хотел бы создать весь invalid объект в цикле, а затем вызвать setState так: setState({invalid: invalid}).

Ошибка в последнем сегменте кода - это просто синтаксическая ошибка. Вы не можете построить такой объект: {invalid[key]:true}, он должен быть {invalid: {[key]: true}}.

+0

Благодарим вас за код. Может быть, '{invalid: {example: true}}' будет работать, но с использованием этого синтаксиса с 'this.setState ((prevState, key))' не работал. Очевидно, что 'key' обрабатывается как имя поля (т. Е.' Invalid: {key: true} ') – Hiroki

+0

Кроме того, я просто заметил, что вы вызываете' setState' с функцией в качестве первого аргумента. Не совсем уверен, откуда вы это взяли, но 'setState' ожидает, что объект будет первым аргументом, который будет сложен в текущее состояние (т. Е. Свойство верхнего уровня будет перезаписано). – forrert

0

Если вы хотите сделать это, способ сделать это:

constructor() { 
    this.state = { 
     input: { 
      example: "", 
     }, 
     invalid:{ 
      example: false 
     }, 
    }; 
} 

assignChildState(state) { 
    var state = Object.assign({}, this.state); 
    state.input = Object.assign({}, state.input); 
    state.input.example = "New Value"; 
    this.setState(state); 
} 

Конечно, вы можете создать функцию, чтобы справиться с этим, что-то вроде:

function assignChildState(path, value) { 
    var pieces = path.split("."); 
    var state = Object.assign({}, this.state); 
    var current = state; 
    for (var i = 0; i < pieces.length - 1; i++) { 
     var piece = pieces[i]; 
     console.log(current, piece); 
     if (current[piece].toString() === "[object Object]") { 
      current[piece] = Object.assign({}, current[piece]); 
     } else if (typeof current[piece] === "object" /* array */) { 
      current[piece] = current[piece].concat(); 
     } 
     current = current[piece]; 
    } 
    current[pieces[i]] = value; 
    this.setState(state); 
} 

И тогда вы можете do:

this.assignChildState("input.example", true); 

и он соответствующим образом обновит дочернее состояние.

Все, что было сказано, я бы определенно рассмотрел сокращение или поток, или мой личный любимый flummox.

Смежные вопросы