Reactjs 优化React组件以使其可重用的最佳方法是什么?
我是React的初学者,目前我只看到了基础知识。我有一个工作任务,就是使OptInPage.jsx中的服务条款组件可重用。我尝试了几件事情,但没有真正理解我在做什么,我查看了文档,但示例似乎比我的问题更基本。 我正在考虑提取页面并创建一个新的TermsOfServices组件来集成jsx标记。 这里的问题是,一方面,应该有一个“只读”属性来防止用户修改内容,另一方面,我真的不知道如何将道具从OptinPage组件传递到新的TermsOfServices组件。 如果我的问题看起来很愚蠢或者类似的话,请提前道歉,我真的被它卡住了。提前感谢您的帮助 OptinPage.jsxReactjs 优化React组件以使其可重用的最佳方法是什么?,reactjs,components,reusability,react-component,Reactjs,Components,Reusability,React Component,我是React的初学者,目前我只看到了基础知识。我有一个工作任务,就是使OptInPage.jsx中的服务条款组件可重用。我尝试了几件事情,但没有真正理解我在做什么,我查看了文档,但示例似乎比我的问题更基本。 我正在考虑提取页面并创建一个新的TermsOfServices组件来集成jsx标记。 这里的问题是,一方面,应该有一个“只读”属性来防止用户修改内容,另一方面,我真的不知道如何将道具从OptinPage组件传递到新的TermsOfServices组件。 如果我的问题看起来很愚蠢或者类似的话
import API from 'api';
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, intlShape } from 'react-intl';
import {
Block,
BlockTitle,
Col,
Fab,
Icon,
Link,
NavRight,
Navbar,
Page,
Popup,
Preloader,
} from 'framework7-react';
import { connect } from 'react-refetch';
import ReactHtmlParser from 'react-html-parser';
import './OptInPage.scss';
class OptInPage extends PureComponent {
static propTypes = {
agreeTosFunc: PropTypes.func.isRequired,
agreeTos: PropTypes.object,
logout: PropTypes.func.isRequired,
onSucceeded: PropTypes.func,
opened: PropTypes.bool.isRequired,
tos: PropTypes.object.isRequired,
};
static contextTypes = {
apiURL: PropTypes.string,
intl: intlShape,
loginToken: PropTypes.string,
logout: PropTypes.func,
userId: PropTypes.string,
};
static defaultProps = {
agreeTos: {},
onSucceeded: () => {},
};
state = {
currentTos: -1,
};
componentDidUpdate(prevProps) {
const {
agreeTos,
onSucceeded,
opened,
tos,
} = this.props;
const { currentTos } = this.state;
/* Reset currentTos on opened */
if (!prevProps.opened && opened) {
this.setState({ currentTos: -1 });
}
/* Prepare for first tos after receiving all of them */
if (
prevProps.tos.pending &&
tos.fulfilled &&
tos.value.length &&
currentTos < 0
) {
this.setState({ currentTos: 0 });
}
/* When sending ToS agreement is done */
if (
prevProps.agreeTos.pending &&
agreeTos.fulfilled
) {
onSucceeded();
}
}
handleNext = () => {
const { agreeTosFunc, tos } = this.props;
const { currentTos: currentTosId } = this.state;
const termsOfServices = tos.value;
const done = currentTosId + 1 === termsOfServices.length;
this.setState({ currentTos: currentTosId + 1 });
if (done) {
agreeTosFunc(termsOfServices.map((v) => v._id));
}
};
render() {
const { logout, opened, tos } = this.props;
const { intl } = this.context;
const { formatMessage } = intl;
const { currentTos: currentTosId } = this.state;
const termsOfServices = tos.value;
const currentTermsOfServices = termsOfServices && termsOfServices[currentTosId];
const loaded = termsOfServices && !tos.pending && tos.fulfilled;
const htmlTransformCallback = (node) => {
if (node.type === 'tag' && node.name === 'a') {
// eslint-disable-next-line no-param-reassign
node.attribs.class = 'external';
}
return undefined;
};
return (
<Popup opened={opened} className="demo-popup-swipe" tabletFullscreen>
<Page id="optin_page">
<Navbar title={formatMessage({ id: 'press_yui_tos_title' })}>
<NavRight>
<Link onClick={() => logout()}>
<FormattedMessage id="press_yui_comments_popup_edit_close" />
</Link>
</NavRight>
</Navbar>
{ (!loaded || !currentTermsOfServices) && (
<div id="optin_page_content" className="text-align-center">
<Block className="row align-items-stretch text-align-center">
<Col><Preloader size={50} /></Col>
</Block>
</div>
)}
{ loaded && currentTermsOfServices && (
<div id="optin_page_content" className="text-align-center">
<h1>
<FormattedMessage id="press_yui_tos_subtitle" values={{ from: currentTosId + 1, to: termsOfServices.length }} />
</h1>
<BlockTitle>
{ReactHtmlParser(
currentTermsOfServices.title,
{ transform: htmlTransformCallback },
)}
</BlockTitle>
<Block strong inset>
<div className="tos_content">
{ReactHtmlParser(
currentTermsOfServices.html,
{ transform: htmlTransformCallback },
)}
</div>
</Block>
<Fab position="right-bottom" slot="fixed" color="pink" onClick={() => this.handleNext()}>
{currentTosId + 1 === termsOfServices.length &&
<Icon ios="f7:check" aurora="f7:check" md="material:check" />}
{currentTosId !== termsOfServices.length &&
<Icon ios="f7:chevron_right" aurora="f7:chevron_right" md="material:chevron_right" />}
</Fab>
{currentTosId > 0 && (
<Fab position="left-bottom" slot="fixed" color="pink" onClick={() => this.setState({ currentTos: currentTosId - 1 })}>
<Icon ios="f7:chevron_left" aurora="f7:chevron_left" md="material:chevron_left" />
</Fab>
)}
</div>
)}
</Page>
</Popup>
);
}
}
export default connect.defaults(new API())((props, context) => {
const { apiURL, userId } = context;
return {
tos: {
url: new URL(`${apiURL}/tos?outdated=false&required=true`),
},
agreeTosFunc: (tos) => ({
agreeTos: {
body: JSON.stringify({ optIn: tos }),
context,
force: true,
method: 'PUT',
url: new URL(`${apiURL}/users/${userId}/optin`),
},
}),
};
})(OptInPage);
从“API”导入API;
从“React”导入React,{PureComponent};
从“道具类型”导入道具类型;
从“react intl”导入{FormattedMessage,intlShape};
进口{
块
区块标题,
上校,
绝妙的,
偶像
链接
没错,
导航栏,
页
弹出窗口,
预载机,
}从“框架7反应”;
从'react refetch'导入{connect};
从“react html parser”导入ReactHtmlParser;
导入“/OptInPage.scss”;
类OptInPage扩展了PureComponent{
静态类型={
AgreetoFunc:PropTypes.func.isRequired,
agreeTos:PropTypes.object,
注销:需要PropTypes.func.isRequired,
onSucceeded:PropTypes.func,
打开:PropTypes.bool.isRequired,
tos:PropTypes.object.isRequired,
};
静态上下文类型={
apiURL:PropTypes.string,
intl:intlShape,
loginToken:PropTypes.string,
注销:PropTypes.func,
userId:PropTypes.string,
};
静态defaultProps={
同意:{},
onSucceed:()=>{},
};
状态={
当前TOS:-1,
};
componentDidUpdate(prevProps){
常数{
同意,
一旦成功,
开的,
托斯,
}=这是道具;
const{currentTos}=this.state;
/*将currentTos重置为打开状态*/
如果(!prevProps.opened&&opened){
this.setState({currentTos:-1});
}
/*收到所有tos后,准备第一个tos*/
如果(
prevProps.tos.pending&&
托斯&&
tos.value.length&&
电流tos<0
) {
this.setState({currentTos:0});
}
/*发送ToS协议时*/
如果(
prevProps.agreeTos.pending&&
同意
) {
onSucceed();
}
}
handleNext=()=>{
const{agreetosunc,tos}=this.props;
const{currentTos:currentTosId}=this.state;
const termsOfServices=tos.value;
const done=currentTosId+1==termsOfServices.length;
this.setState({currentTos:currentTosId+1});
如果(完成){
AgreetoFunc(termsOfServices.map((v)=>v._id));
}
};
render(){
const{logout,opened,tos}=this.props;
const{intl}=this.context;
const{formatMessage}=intl;
const{currentTos:currentTosId}=this.state;
const termsOfServices=tos.value;
const currentsofservices=termsOfServices&&termsOfServices[currentsofid];
const loaded=条款服务&&!tos.pending&&tos.COMPLETED;
常量HTMLTransferMcCallback=(节点)=>{
if(node.type=='tag'&&node.name=='a'){
//eslint禁用下一行无参数重新分配
node.attribs.class='external';
}
返回未定义;
};
返回(
注销()}>
{(!loaded | |!currentTermsOfServices)&&(
)}
{loaded&¤tTermsOfServices&&(
{ReactHtmlParser(
currentTermsOfServices.title,
{transform:htmlTransferMcCallback},
)}
{ReactHtmlParser(
currentTermsOfServices.html,
{transform:htmlTransferMcCallback},
)}
this.handleNext()}>
{currentTosId+1==termsOfServices.length&&
}
{currentTosId!==termsOfServices.length&&
}
{currentTosId>0&&(
this.setState({currentTos:currentTosId-1})}>
)}
)}
);
}
}
导出默认的connect.defaults(新API())((道具,上下文)=>{
const{apirl,userId}=context;
返回{
tos:{
url:newURL(`${APIRL}/tos?过时=false&required=true`),
},
同意功能:(tos)=>({
同意:{
body:JSON.stringify({optIn:tos}),
上下文
原力:没错,
方法:'放',
url:新url(`${APIRL}/users/${userId}/optin`),
},
}),
};
})(可选页);
如果我没听错,你需要这样的短信。
首先,您需要使用组件创建一个新文件,并将下一个代码放在那里
// don't forget to clean the unused imports
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, intlShape } from 'react-intl';
import {Block, BlockTitle, Col, Fab, Icon, Link, NavRight, Navbar, Page, Popup, Preloader } from 'framework7-react';
import ReactHtmlParser from 'react-html-parser';
export default class YourCLassName extends PureComponent<Props, State> {
static propTypes = {
currentTosId: PropTypes.object, // write correct type here
termsOfServices: PropTypes.object, // write correct type here
currentTermsOfServices: PropTypes.string, // write correct type here
handleNext: PropTypes.func, // write correct type here
handlePrev: PropTypes.func, // write correct type here
};
function htmlTransformCallback (node) => {
if (node.type === 'tag' && node.name === 'a') {
// eslint-disable-next-line no-param-reassign
node.attribs.class = 'external';
}
return undefined;
};
render() {
const { currentTosId, termsOfServices, currentTermsOfServices } = this.props;
return (
<div id="optin_page_content" className="text-align-center">
<h1>
<FormattedMessage id="press_yui_tos_subtitle" values={{ from: currentTosId + 1, to: termsOfServices.length }} />
</h1>
<BlockTitle>
{ReactHtmlParser(
currentTermsOfServices.title,
{ transform: htmlTransformCallback },
)}
</BlockTitle>
<Block strong inset>
<div className="tos_content">
{ReactHtmlParser(
currentTermsOfServices.html,
{ transform: htmlTransformCallback },
)}
</div>
</Block>
<Fab position="right-bottom" slot="fixed" color="pink" onClick={() => this.props.handleNext()}>
{currentTosId + 1 === termsOfServices.length &&
<Icon ios="f7:check" aurora="f7:check" md="material:check" />}
{currentTosId !== termsOfServices.length &&
<Icon ios="f7:chevron_right" aurora="f7:chevron_right" md="material:chevron_right" />}
</Fab>
{currentTosId > 0 && (
<Fab position="left-bottom" slot="fixed" color="pink" onClick={() => this.props.handlePrev())}>
<Icon ios="f7:chevron_left" aurora="f7:chevron_left" md="material:chevron_left" />
</Fab>
)}
</div>
);
}
}
//不要忘记清理未使用的导入
从“React”导入React,{PureComponent};
从“道具类型”导入道具类型;
从“react intl”导入{FormattedMessage,intlShape};
从“framework7 react”导入{Block、BlockTitle、Col、Fab、Icon、Link、NavRight、Navbar、Page、Popup、preload};
从“react html parser”导入ReactHtmlParser;
导出默认类YourCLassName扩展PureComponent{
静态类型={
currentTosId:PropTypes.object,//在此处写入正确的类型
termsOfServices:PropTypes.object,//write
<YourComponentName currentTosId={this.state.currentTosId} termsOfServices={termsOfServices} currentTermsOfServices={currentTermsOfServices} handleNext={this.handleNext} handlePrev={this.handlePrev} />