如何让子组件控制根组件中的React钩子

时间:2019-04-09 18:33:35

标签: javascript reactjs react-hooks

我有一个将GitHub用户添加到列表的应用程序。当我在表单中输入内容时,将返回一个用户并将其添加到列表中。我希望仅在用户在资源请求后出现时单击该用户时,才将其添加到列表中。具体来说,我想要的是在子组件中具有click事件,以触发根组件对钩子的触发,以将新元素添加到列表中。

根组件

const App = () => {
  const [cards, setCards] = useState([])

  const addNewCard = cardInfo => {
    console.log("addNewCard called ...")
    setCards([cardInfo, ...cards])
  }

  return (
    <div className="App">
      <Form onSubmit={addNewCard}/>
      <CardsList cards={cards} />
    </div>
  )
}

export default App;

表单组件

const Form = props => {
    const [username, setUsername] = useState('');

    const chooseUser = (event) => {
        setUsername(event.target.value)
    } 

    const handleSubmit = event => {
        event.persist();
        console.log("FETCHING ...")
        fetch(`http://localhost:3666/api/users/${username}`, {
        })
        .then(checkStatus)
        .then(data => data.json())
        .then(resp => {
            console.log("RESULT: ", resp)
            props.onSubmit(resp)
            setUsername('')
        })
        .catch(err => console.log(err))
    }

    const checkStatus = response => {
        console.log(response.status)
        const status = response.status
        if (status >= 200 && status <= 399) return response
        else console.log("No results ...")
    }

    return (
        <form onSubmit={handleSubmit}>
            <input
                type="text"
                placeholder="Gitbub username"
                value={username}
                required
                onChange={chooseUser}
                onKeyUp={debounce(handleSubmit, 1000)}
            />
            <button type="submit">Add card</button>
        </form>
    )
}
export default Form;

列表组件

const CardsList = props => {

    return (
        <div>
            {props.cards.map(card => (
                <Card key={card.html_url} {... card} 
                />
            ))}
        </div>
    )
}

export default CardsList

和卡组件

const Card = props => {

    const [selected, selectCard] = useState(false)

    return (
        <div style={{margin: '1em'}}>
            <img alt="avatar" src={props.avatar_url} style={{width: '70px'}} />
            <div>
                <div style={{fontWeight: 'bold'}}><a href={props.html_url}>{props.name}</a></div>
                <div>{props.blog}</div>
            </div>

        </div>
    )
}

export default Card 

现在,我的Form组件拥有所有控件。如何将App中的addNewCard方法控制在Card子组件上?

预先感谢一百万。

1 个答案:

答案 0 :(得分:0)

一个解决方案可能是在App中创建removeCard方法,如果您要控制addNewCard的click事件没有发生,则将触发该方法。

// App.js
...
const removeCard = username => {
    console.log("Tried to remove card ....", username)
    setCards([...cards.filter(card => card.name != username)])
  }

然后将removeCard和addNewCard都传递给CardList。

// App.js
...
  <CardsList remove={removeCard} cards={cards} add={addNewCard}/>

继续并将这些方法传递给CardsList中的Card。您还需要分配给布尔值的卡片上的一些道具,例如“ selected”。

// CardsList.js
 return (
        <div>
            {props.cards.map(card => (
                <Card key={card.html_url} {... card} 
                remove={handleClick} 
                add={props.add}
                selected={false}
                />
            ))}
        </div>

在子Card组件中设置钩子和click事件,

// Card.js
...
const [selected, selectCard] = useState(false)
...

并配置事件以触发挂接并使用状态。

// Card.js
...

    return (
        <div style={{margin: '1em', opacity: selected ? '1' : '0.5'}}
            onMouseLeave={() => selected ? null : props.remove(props.name)}
            onClick={() => selectCard(true)}
        >
...

这并没有真正将addNewCard的控制从窗体转移到Card,但是最终迫使UI遵循Card组件的状态。