在典型的基于类的React组件中,这就是创建事件处理程序的方式:
class MyComponent extends Component {
handleClick = () => {
...
}
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
Run Code Online (Sandbox Code Playgroud)
但是,当我使用基于钩子的功能范例时,发现有两个选择:
const MyComponent = () => {
const [handleClick] = useState(() => () => {
...
});
return <button onClick={handleClick}>Click Me</button>;
};
Run Code Online (Sandbox Code Playgroud)
或者:
const MyComponent = () => {
const handleClick = useRef(() => {
...
});
return <button onClick={handleClick.current}>Click Me</button>;
};
Run Code Online (Sandbox Code Playgroud)
客观上哪个更好,出于什么原因?还有我还没有听说过的(更好)方法吗?
谢谢您的帮助。
编辑:我在CodeSandbox上放了一个示例,显示了这两种方法。正如您从那里的代码可以看到的那样,似乎都没有必要在每个渲染器上重新创建事件处理程序,因此,我认为不可能出现性能问题。
假设我有一个带有两个子组件的父组件:
const Parent = () => {
const [myVar, setmyVar] = useState(false)
return (
<>
<MyChildComponent1 myVar={myVar} setMyVar={setMyVar} \>
<MyChildComponent2 myVar={myVar} \>
</>
)
}
Run Code Online (Sandbox Code Playgroud)
现在我将如何正确设置类型MyChildComponent2?
这是我到目前为止想出的:
const MyChildComponent1 = (
{myVar, setMyVar}:
{myVar: boolean, setMyVar: (value: boolean) => void}) = (...)
Run Code Online (Sandbox Code Playgroud)
类型是否setMyvar正确?或者应该是别的什么?
我试图根据个人是否在组件上向下滚动来控制 React 组件的可见性。可见性Fade作为“in”属性传递到元素中。
我已经使用 UseEffect Hook 设置了一个侦听器,它添加了 onMount 侦听器。实际的 onScroll 函数应该更新 scrollTop 状态(它是到页面顶部的高度的当前值),然后是滚动状态(将事件的滚动到页面顶部与之前的状态进行比较,以及如果第一个大于第二个,则返回 true)。
但是,由于某种原因 setScrollTop 钩子不起作用,滚动状态继续保持在 0。
我究竟做错了什么?这是完整的组件:
export const Header = (props) => {
const classes = useStyles();
const [scrolling, setScrolling] = useState(false);
const [scrollTop, setScrollTop] = useState(0);
const onScroll = (e) => {
setScrollTop(e.target.documentElement.scrollTop);
setScrolling(e.target.documentElement.scrollTop > scrollTop);
}
useEffect(() => {
window.addEventListener('scroll', onScroll);
},[]);
useEffect(() => {
console.log(scrollTop);
}, [scrollTop])
return (
<Fade in={!scrolling}>
<AppBar className={classes.header} position="fixed">
....
Run Code Online (Sandbox Code Playgroud) 从文档:
[init, the 3d argument] 允许您提取用于计算 reducer 之外的初始状态的逻辑。这对于稍后响应动作重置状态也很方便。
和代码:
function init(initialCount) {
return { count: initialCount };
}
function reducer(state, action) {
switch (action.type) {
...
case 'reset':
return init(action.payload);
...
}
}
function Counter({initialCount}) {
const [state, dispatch] = useReducer(reducer, initialCount, init);
...
}
Run Code Online (Sandbox Code Playgroud)
为什么我会在重用常量时这样做initialState?
const initialState = {
count: 5,
};
function reducer(state, action) {
switch (action.type) {
...
case 'reset':
return initialState;
...
}
}
function Counter({initialCount}) {
const [state, dispatch] = useReducer(reducer, …Run Code Online (Sandbox Code Playgroud) 我有一个非常基本的自定义钩子,它接受一个路径并从 firebase 返回一个文档
import React, { useState, useEffect, useContext } from 'react';
import { FirebaseContext } from '../sharedComponents/Firebase';
function useGetDocument(path) {
const firebase = useContext(FirebaseContext)
const [document, setDocument] = useState(null)
useEffect(() => {
const getDocument = async () => {
let snapshot = await firebase.db.doc(path).get()
let document = snapshot.data()
document.id = snapshot.id
setDocument(document)
}
getDocument()
}, []);
return document
}
export default useGetDocument
Run Code Online (Sandbox Code Playgroud)
然后我使用 useEffect 作为 componentDidMount/constructor 来更新状态
useEffect(() => {
const init = async () => {
let docSnapshot …Run Code Online (Sandbox Code Playgroud) 考虑这个例子:
let memoizedCb = React.useCallback(
memoize((param) => () => someFunction(param)),
[]
);
Run Code Online (Sandbox Code Playgroud)
哪里memoize来自外部库,例如“fast-memoize”。上面的代码给出了警告:
React Hook useCallback 收到一个依赖项未知的函数。改为传递内联函数
我发现这个线程,如果我们适应我的用例,会建议将此作为解决方案(如果我没有错的话):
const memoizedCb = React.useMemo(
() => memoize((param) => () => someFunction(param)),
[]
);
Run Code Online (Sandbox Code Playgroud)
警告是关于什么的?为什么要useMemo解决这个问题?
注意:someFunction在函数组件之外定义,因此不需要将其作为依赖项。
我正在试验React中的新Hook功能.考虑到我有以下两个组件(使用React Hooks) -
const HookComponent = () => {
const [username, setUsername] = useState('Abrar');
const [count, setState] = useState();
const handleChange = (e) => {
setUsername(e.target.value);
}
return (
<div>
<input name="userName" value={username} onChange={handleChange}/>
<p>{username}</p>
<p>From HookComponent: {count}</p>
</div>
)
}
const HookComponent2 = () => {
const [count, setCount] = useState(999);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
钩权利要求来解决的共享部件之间的有状态逻辑的问题,但我发现之间的状态HookComponent和HookComponent2不共享.例如,countin 的改变HookComponent2 …
我正在玩React钩子并面临一个问题.当我尝试使用事件监听器处理的按钮来控制日志时,它显示错误的状态.
CodeSandbox: https ://codesandbox.io/s/lrxw1wr97m
为什么它显示错误的状态?在第一张卡中,Button2应在控制台中显示2张卡.有任何想法吗?
import React, { useState, useContext, useRef, useEffect } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const CardsContext = React.createContext();
const CardsProvider = props => {
const [cards, setCards] = useState([]);
const addCard = () => {
const id = cards.length;
setCards([...cards, { id: id, json: {} }]);
};
const handleCardClick = id => console.log(cards);
const handleButtonClick = id => console.log(cards);
return (
<CardsContext.Provider
value={{ cards, addCard, handleCardClick, handleButtonClick }}
>
{props.children} …Run Code Online (Sandbox Code Playgroud)在useContextReact 16.8+上使用钩子效果很好。您可以创建一个组件,使用该钩子并利用上下文值而不会出现任何问题。
我不确定的是如何将更改应用于Context Provider值。
1)useContext挂钩是否严格地是一种使用上下文值的方法?
2)是否有推荐的方法,使用React挂钩来更新子组件的值,然后该子组件将使用useContext带有此上下文的挂钩触发任何组件的组件重新渲染?
const ThemeContext = React.createContext({
style: 'light',
visible: true
});
function Content() {
const { style, visible } = React.useContext(ThemeContext);
const handleClick = () => {
// change the context values to
// style: 'dark'
// visible: false
}
return (
<div>
<p>
The theme is <em>{style}</em> and state of visibility is
<em> {visible.toString()}</em>
</p>
<button onClick={handleClick}>Change Theme</button>
</div>
)
};
function App() {
return <Content />
};
const rootElement = …Run Code Online (Sandbox Code Playgroud)在 JS 中,两个对象不相等。
const a = {}, b = {};
console.log(a === b);
Run Code Online (Sandbox Code Playgroud)
所以我不能在useEffect(React hooks)中使用一个对象作为第二个参数,因为它总是被认为是假的(所以它会重新渲染):
const a = {}, b = {};
console.log(a === b);
Run Code Online (Sandbox Code Playgroud)
这样做(上面的代码),每次组件重新渲染时都会产生运行效果,因为每次都认为对象不相等。
我可以通过将对象作为 JSON 字符串化值传递来“破解”它,但这有点脏 IMO:
function MyComponent() {
// ...
useEffect(() => {
// do something
}, [myObject]) // <- this is the object that can change.
}
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来做到这一点并避免不必要的效果调用?
旁注:对象具有嵌套属性。效果必须在此对象内的每个更改上运行。
react-hooks ×10
reactjs ×10
javascript ×8
json ×1
jsx ×1
react-props ×1
typescript ×1
use-reducer ×1
usecallback ×1