问题:
如何将反应组件的方法暴露给其他地方?
例如,我想从React之外的元素调用React-Router的this.context.router.push(location)。
也许我可以在窗口对象中添加一个React组件的方法,以便可以从任何通用DOM事件监听器甚至控制台调用它?
背景/使用案例
我想在我的React应用程序中使用jQuery DataTables,因为它提供了许多在React生态系统中仍然无法使用的插件和配置。
我从现有的React数据表组件开始(下面的实现)。
原始提供了传递渲染函数的不错选项,例如,渲染单元格内的其他React组件。下面是“产品名称”中的单元格。列呈现为React-Router<链接/>组件。
const data = [
{
product_id: '5001',
product_price: '$5',
product_name: 'Apple'
},
...
];
const renderUrl =
(val, row) => {
return (<Link to={`/product/${row.product_id}`}>{row.product_name}</Link>);
};
const columns = [
{ title: 'Product Name', prop: 'product_id', render: renderUrl },
{ title: 'Price', prop: 'product_price' },
];
<DataTable
className="datatable-container"
columns={columns}
initialData={data}
/>
我修改现有组件所做的工作涉及将表隐藏在React的DOM差异算法中,因为当jQuery DataTables修改DOM时它会破坏。
render()现在输出一个空的div,其中包含 ref 和 id
render() {
return (
<div>
<div ref="dtContainer" id="dtContainer"></div>
</div>
);
}
componentDidMount使用ReactDomServer.renderToStaticMarkup将React组件转换为普通的非反应标记,并将其附加到render()的#dtContainer div中。最后,jQuery DataTables将渲染的表格html初始化为一个奇特的jQuery DataTable&#39;。
componentDidMount() {
let table = this.getDTMarkup();
let dtContainer = this.refs.dtContainer;
let renderedTable = ReactDOMServer.renderToStaticMarkup(table, dtContainer);
$('#dtContainer').append(renderedTable);
let jqueryTable = $('#dt'); // hard coded in getDTMarkup() for now
// Turn html table into a jQuery DataTable with desired config options
jqueryTable.DataTable({
dom: '<"html5buttons"B>lTfgitp',
buttons: [
'copy', 'csv', 'excel', 'pdf', 'print'
],
"pagingType": 'numbers',
"bAutoWidth": false,
"bDestroy": true,
"fnDrawCallback": function() {
console.log('datatables fnDrawCallback');
}
});
}
src https://github.com/alecperkey/react-jquery-datatables/blob/master/src/Table.js#L89-L111
我问这个问题的限制是我现在无法使用React组件,例如&lt;链接/&gt;在这个静态的非React标记里面。我正在使用&lt; a href =&#34;&#34;&gt;现在,但是这将重新加载页面,这会更慢并导致浏览器的白色闪烁。
答案 0 :(得分:1)
这就是我设法将方法从React组件公开到“全局”作用域或在React应用之外的方式。 我真的不太了解您的案子细节,但这可能对您有用。另外,我使用钩子,但是这也应该适用于旧式生命周期方法。
想象这是我的组件。它只是呈现由国家管理的数字。
const MyCount = ({ getMethods }) => {
const [state, setState] = useState(1);
useEffect(() => {
getMethods({ setState });
}, []);
return <h1>{state}</h1>;
}
您看到,getMethods
是使其工作的关键。该函数将在安装组件时执行,并将提供我需要作为参数公开的方法。在这种情况下,setState
方法。
现在,让我们假装我想在反应之外使用一个按钮来触发该方法。
// I want to store the methods in this variable
let globalMethods;
// When rendering the react component I pass the prop `getMethods`
// that will assign the returned value
React.render(<MyCount getMethods={methods => globalMethods = methods} />, $someEl);
// Now I can use it outside
$("#myButton").click(() => {
globalMethods.setState(2);
})
希望这会有所帮助。或者,因为已经晚了3.9年,您甚至不再需要此功能。
答案 1 :(得分:-1)
有几种方法可以将React组件与“外部应用程序”连接起来
您可以将方法作为道具传递给组件,如:
const foo = function(){
alert(1)
}
class HelloWorldComponent extends React.Component {
render() {
return (
<h1 onClick={(e) => this.props.cb()}>Hello {this.props.name}</h1>
);
}
}
React.render(
<HelloWorldComponent cb={foo} name="Joe Schmoe"/>,
document.getElementById('react_example')
);
http://jsbin.com/zujebirusa/1/edit?js,output
使用附加到窗口的全局方法。请记住,它很难维护,因为它会污染全局命名空间。
window.foo = function(){
alert(1)
}
class HelloWorldComponent extends React.Component {
render() {
return (
<h1 onClick={(e) => window.foo()}>Hello {this.props.name}</h1>
);
}
}
React.render(
<HelloWorldComponent name="Joe Schmoe"/>,
document.getElementById('react_example')
);
http://jsbin.com/woyokasano/1/edit?js,output
使用ES6模块系统以使代码库保持整洁的范围
//methods.js
export function foo() {
alert(1)
}
import {foo} from './methods';
class HelloWorldComponent extends React.Component {
render() {
return (
<h1 onClick={(e) => foo()}>Hello {this.props.name}</h1>
);
}
}
React.render(
<HelloWorldComponent name="Joe Schmoe"/>,
document.getElementById('react_example')
);