根据另一个组件的状态更改React组件可见性

时间:2019-12-02 14:19:35

标签: javascript reactjs

我创建了以下React组件。它使用输入框来接受用户对谜语的回答。用户的输入与所需答案匹配后,输入框将变为只读(使用它们的方式有些奇怪)。它还有一个“ isHidden”道具来确定是否渲染了谜语。

class Riddle extends React.Component {
  constructor(props) {
    super(props);
    this.answer = props.answer.toUpperCase();
    this.state = {
      text: "",
      isAnswered: false
    };

    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    let userInput = event.target.value.toUpperCase();
    if (userInput == this.answer) {
      this.setState({
        text: userInput,
        isAnswered: true
      });
    } else {
      this.setState({
        text: userInput,
        isAnswered: false
      });
    }
  }

  render() {
    if (this.props.isHidden) {
      return <div></div>;
    } else {
      return (
        <div>
          <p>{this.props.prompt}</p>
          <input type="text" value={this.state.text} 
          readOnly={this.state.isAnswered}></input>
        </div>
      );
    }
  }
}

在实践中:

function App() {
  return (
    <div>
      <Riddle prompt='The first three letters in the alphabet.' answer="abc" isHidden="false"/>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));

我想做的是按顺序排列一堆这些谜语,但是只有在解决前一个谜语时才能看到这些谜语。问题在于我不知道如何导致可见性更新发生。

我已经阅读了有关将状态从子级提升到父级组件的信息,并且尝试查看是否可以创建一个RiddleSequence作为其子级的Riddle组件,并使用{{1 }}管理可见性。我的问题是,目前RiddleSequence的状态是否得到解决是其一部分,并且我不知道Riddle如何读取该信息,因为子状态应该保持隐藏。这似乎是封装RiddleSequence功能的一种合理方法,但是考虑到我的目标,也许我错了。

我还考虑过让Riddle成为他们赖以生存的其他谜语的孩子,因为我可以将状态/道具传递给孩子:

Riddle

但是,如果我有一个带有100个谜语的应用,这似乎太荒谬了。这也降低了灵活性,可用于更多扩展的功能集(例如使一个谜语取决于一组3个谜语)。

如何使<Riddle prompt="first riddle"...> <Riddle prompt="depends on first riddle"...> <Riddle prompt="depends on second riddle"...> </Riddle> </Riddle> </Riddle> 组件的可见性取决于其他谜语的状态?

1 个答案:

答案 0 :(得分:1)

一个简单的解决方案是拥有您所说的容器组件:

class Riddle extends Component {
    constructor(props) {
        this.state = {
            text: ''
        }
        this.answer = props.answer.toUpperCase()
    }

    handleChange = event => {
        const userInput = event.target.value.toUpperCase()
        const callback = userInput == this.answer ? this.props.onSolved : undefined
        this.setState({ text: userInput }, callback)
    }

    render() {
        const { text, isAnswered } = this.state
        const { prompt } = this.props
        if (this.props.isHidden) {
            return null
        }
        return (
            <div>
                <p>{prompt}</p>
                <input type="text" value={text} readOnly={isAnswered}></input>
            </div>
        )
    }
}

并且容器应具有这样的可见性:

class RiddleSequence extends Component {
    state = {}

    riddles = [
        {
            id: 1,
            prompt: 'The first three letters in the alphabet.',
            answer: 'abc',
            prev: null
        },
        {
            id: 2,
            prompt: 'The last three letters in the alphabet.',
            answer: 'xyz',
            prev: 1
        }
    ]

    render() {
        return (
            <div>
                {this.riddles.map(r => {
                    const { id, prev } = r
                    const visible = !prev || this.state[prev]
                    return (
                        <Riddle
                            key={id}
                            isHidden={!visible}
                            onSolved={() => this.setState({ [r.id]: true })}
                            {...r}
                        />
                    )
                })}
            </div>
        )
    }
}