在函数Javascript/React中使用字符串动态调用函数/变量



我正试图找到一种方法来动态调用给定字符串的函数或引用给定字符串的变量。例如:

import React, {useState} from 'react'
const array = [
{
text: 'count1',
setFunctionName: 'setCount1',
otherdata: {}
},
{
text: 'count2',
setFunctionName: 'setCount2',
otherdata: {}
}
]
const myFunction = () => {
const  [count1, setCount1] = useState(0)
const  [count2, setCount2] = useState(0)
return(
<div>
{array.map((item) => {
// I want to use item.text to reference the correct count variable
// I want to use item.setFunctionName to change the correct count 
})}
</div>
)
}

具体的用例是我想创建一个可重用的侧边栏菜单,其中链接的数据存储在一个单独文件中的对象数组中。一些菜单项将有可折叠的子菜单,我需要管理使用状态的子菜单的打开和关闭。例子:

import { Button, Collapse } from 'react-bootstrap'
function Example() {
const [open, setOpen] = useState(false);

return (
<>
<Button
onClick={() => setOpen(!open)} //**I want to dynamically set this when mapping over the array**
>
click
</Button>
<Collapse in={open}> //**I want to dynamically set this when mapping over the array**
<div id="example-collapse-text">
This is example collapsed text
</div>
</Collapse>
</>
);
}

最好的方法可能是使用减速器。

https://reactjs.org/docs/hooks-reference.html usereducer

也许是这样的?

const initialState = {count1: 0, count2: 0};
function reducer(state, action) {
switch (action.type) {
case 'setCount1':
return {
...state,
count1: action.value
};
case 'setCount2':
return {
...state,
count2: action.value
};
default:
throw new Error();
}
}
const array = [
{
text: 'count1',
setFunctionName: 'setCount1',
otherdata: {}
},
{
text: 'count2',
setFunctionName: 'setCount2',
otherdata: {}
}
]
const myFunction = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return(
<div>
{array.map((item) => {
return <a onClick={ () => dispatch({ type: item.setFunctionName, value:3 }) }>{state[item.text]} <a/>
})}
</div>
)
}

如果你不想一直移动到useReducer,那么也可以将对象保存到useState,而不是为每个单独的字段调用单独的useState:

import React, {useState} from 'react'
const array = [
{
text: 'count1',
otherdata: {}
},
{
text: 'count2',
otherdata: {}
}
]
const myFunction = () => {
// This could even be initialised based on the items in `array`
const  [count, setCount] = useState({
count1: 0,
count2: 0,
});
return(
<div>
{array.map((item, index) => {
// I want to use item.text to reference the correct count variable
const countValue = count[item.text];

const updateCount = () => {
setCount((prevCount) => {
return {
...prevCount,
[item.text]: prevCount[item.text] + 1,
};
});
};

return (
<button key={index}
onClick={updateCount}
>{item.text}: { countValue }</button>
);
})}
</div>
)
}

你可以使用它的名字动态地调用函数,像这样:

步骤1:将函数存储在对象中:

const objectOfFunctions = {
stepOne: () => "This is the step number 1",
stepTwo: () => "This is the step number 2",
stepTree: () => "This is the step number 3"
}

步骤2:然后你可以在你的反应组件中这样调用它们:{objectOfFunctions['stepTwo']()}


例子:

import React, { useState } from "react";
const objectOfFunctions = {
stepOne: () => "This is the step number 1",
stepTwo: () => "This is the step number 2",
stepTree: () => "This is the step number 3"
}
export default function App() {
return <div>
{
Object.keys(objectOfFunctions).map( (e, index) => (
<h3 key={index}>
{objectOfFunctions[e]()}
</h3>
))
}
</div>
}

或者您可以将存储在数据库中的函数解析为字符串。在运行时使用这个组件访问JSX:(这很危险)react-jsx-parser

这样你就可以有一个像这样的字符串:

const str = 'This is a component rendered in runtime {Component}'它会起作用的。

然而

我认为这不是你的用例所需要的,我所理解的是你想要一个带有子菜单的菜单。

你需要我们的主和救世主递归.

import { Link } from 'react-router-dom'
const data = [
{
name: 'Menu 1',
url: '/',
childrens: [{
name: 'Sub Menu 1',
url: '/site-1',
childrens: [{
name: 'Sub Menu 1.1',
url: '/site-1-1',
childrens: []
}]
}]
},
{
name: 'Menu 2',
url: '/site-2',
childrens: []
}
]
const App = () => {
return <div>
<Component data={ data } />
</div>
}
const Component = ({ data }) => {
return <div>
{
data.map(element => (
<Link to={ element.url } >
{ element.name }
<Component data={ data.childrens } /> {/* This renders itself again but withh it's childrens */}
</Link>
))
}
</div>
}

我可能是错的,但听起来如果你正在使用react-bootstrap,你可能想要使用accordion组件,因为它可能看起来和行为更接近你所寻找的。但无论哪种方式,填充在展开时显示的内容都将得到类似的处理。如果扩展的内容保存在状态对象中,它应该在状态更改时自动更新。您可以映射给定的数组并呈现JSX

<Collapse in={open}> //**I want to dynamically set this when mapping over the array**
array.map(element => {
return(
<div>
{element.text
element.setFunctionName}
</div>
)
})
</Collapse>

这是这个过程的一个非常简单的应用。这里要说明的一点是,如果映射到一个对象数组,则可以为每个数组元素呈现JSX。这可以是任何JSX,甚至是您创建的组件。这是非常强大的,因为这些组件可以保持自己的状态和行为,并将在折叠区域中表现得像这样。

另外,如果数组的内部对象也需要有折叠功能,您可以在映射元素中执行相同的JSX。在这方面,天空是无限的。

相关内容

最新更新