React功能组件-如何计算实例



我需要能够跟踪我的组件的实例数量,我如何在React中使用功能组件来做到这一点?

我尝试使用useRef(),但看起来即使它在渲染之间保留了值,它也不会在组件实例之间共享值。

到目前为止,我想出的唯一解决方案就是这个笨拙的解决方案,我希望有一种方法可以以更优雅的方式存储它。

const [ ident, setIdent ] = useState(0);
useEffect(() => {
if (document.sometring === undefined) {
document.sometring = 0;
} else {
document.sometring++;
}
setIdent(document.sometring);
}, []);

问题更新:用例更实际,我想知道如何做,而不是实用。我希望我的独立组件的每个实例都有唯一的序列ID(如"button-42"(,所以这就是为什么像"给它一个随机代码"这样的解决方案对我来说也不起作用。像redux或context这样的全局状态管理器也不能成为解决方案,如果我在GitHub上开源我的组件,我不应该要求用户安装redux或使用React.Context。当然,如果组件重新呈现,这个ID也不应该改变。

您可以使用useStateuseEffect的初始化函数(如果您不需要组件中的更新值(来增加计数器,并将initialState设置为新值:

/** export **/ const count = { val: 0 };
const Comp = ({ force }) => {
// if you don't need the value inside the component on render, you can replace with useEffect(() => (count.val++, count.val), [])
const [id] = React.useState(() => ++count.val); 

return <div>{force} Count {id}</div>;
}
const Demo = () => {
const [force, setForce] = React.useState(0);
return (
<div>
<Comp force={force} />
<Comp force={force} />
<Comp force={force} />

<button onClick={() => setForce(force + 1)}>Force Render</button>
</div>
);
}
ReactDOM.render(
<Demo />,
root
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>

如果您想跟踪应用程序中活动组件的数量(忽略以前渲染但现在不再渲染的组件(

const count = { value: 0 }
export { count }
const incrementCounter = () => count.value++
const decrementCounter = () => count.value--
// ...
useEffect(() => {
incrementCounter();
return decrementCounter; // will run on "unmount"
}, []); // run this only once

当然,如果你想在应用程序的其他地方显示这个计数,你需要让它成为反应性的-例如,将incrementCounterdecrementCounter功能作为道具,并在组件或Redux的状态中的某个地方更新计数器(或者由使用该组件的人决定(

Redux解决方案

Dom输出:

嗨,我的id是0

嗨,我的id是1

嗨,我的id是2

嗨,我的id是3

嗨,我的id是4

实例总数:5

反应侧:

SomeTrackedComponent.js

export default const SomeTrackedComponent = ({id}) => (
<div> hi my id is {id} </div>
)

App.js

const App = ({instances , addInstance}) =>{
const [trackedComponents, setTrackedComponents] = useState([]);
useEffect(()=>{
const justSomeArray = Array.from(Array(5).keys())
//wont have access to updated instance state within loop so initialize index
const someJSX = justSomeArray.map((_, id = instances.currentId )=>{ 
addInstance({ id , otherData: 'otherData?'})
return <SomeTrackedComponent key={id} id={id} />
})

setTrackedComponents(someJSX)
},[])
return( 
<div>
{trackedComponents}
Total instances: {instances.items.length}
</div>
)
}
export default connect(
({instances})=>({instances}),
actions
)(App);

Redux侧:

actions.js

export const addInstance = (payload) =>(
{type:'CREATE_INSTANCE' , payload}
)
export const removeInstance = (payload) =>(
{type:'REMOVE_INSTANCE' , payload}
)

reducers.js

const instanceReducer = (state = { items : [] , currentId : 1} , action) => {
switch (action.type) {
case 'CREATE_INSTANCE':
return {
currentId: state.currentId + 1
items:[...state.items , action.payload],
}
case 'REMOVE_INSTANCE':
return {
...state,
items: [...state.items].filter(elm => elm.id !== action.payload.id)
}
default:
return state;
}
}
export default combineReducers({
instances: instanceReducer
})

Index.js:

// import React from 'react';
// import ReactDOM from 'react-dom';
// import { Provider } from 'react-redux';
// import { createStore  } from 'redux';
// import reducers from './redux/reducers';
// import App from './components/App';

ReactDOM.render(
<Provider store={createStore(reducers)}>
<App />
</Provider>,
document.querySelector('#root')
);

相关内容

  • 没有找到相关文章

最新更新