本文共 12473 字,大约阅读时间需要 41 分钟。
初学react实现路由跳转
This is part of my “React for beginners” series on introducing React, its core features and best practices to follow. More articles are coming!
这是我的“初学者React”系列的一部分,该系列介绍了React,其核心功能和可遵循的最佳实践。 更多文章来了!
|
|
As you can tell from the title of this article, it’s aimed at beginners.
从本文标题可以看出,它是针对初学者的。
Actually, I started to learn React a few months ago. Reading the React documentation, open source projects, and Medium articles has helped me a lot.
实际上,我是几个月前开始学习React的。 阅读React文档,开源项目和Medium文章对我有很大帮助。
Without a doubt, I’m not an expert in React. And so I read a lot about this topic. Also, building a small projects has helped me get to know React better. Along the way, I’ve adopted some best practices — and I want to share with you here. So let’s get started.
毫无疑问,我不是React的专家。 因此,我阅读了很多有关该主题的文章。 此外,构建一个小型项目还帮助我更好地了解了React。 在此过程中,我采用了一些最佳做法-我想在这里与您分享。 因此,让我们开始吧。
To figure which component has a bug, it’s important to always give your component a name.
要弄清楚哪个组件存在错误,务必始终为您的组件命名。
Even more so when you begin to use React Router or third party libraries.
在您开始使用React Router或第三方库时,更是如此。
// Avoid thoses notations export default () => {};export default class extends React.Component {};
There is a debate about whether to use a default or named import. Note that a default import doesn’t ensure that the component’s name is consistent in the project. Besides, will be less effective.
关于使用默认导入还是命名导入存在争议。 请注意, 默认导入不能确保组件名称在项目中保持一致。 此外, 将不太有效。
You need to define the class name or the variable name (for functional components) that’s hosting the component.
您需要定义托管组件的类名或变量名(对于功能组件)。
React will actually from it in error messages.
React实际上会在错误消息中从中 。
export const Component = () =>I'm a component
;export default Component;// Define user custom component nameComponent.displayName = 'My Component';
Here’s my last piece of advice about imports (taken from ): If you use ESLint, you should consider setting the following two rules:
这是我有关导入的最后一条建议(从 ):如果使用ESLint,则应考虑设置以下两个规则:
"rules": { // Check named import exists "import/named": 2, // Set to "on" in airbnb preset "import/prefer-default-export": "off"}
If you have many components whose purpose is only to display data, take advantage of the many ways to :
如果您有许多仅用于显示数据的组件,请利用多种方法来 :
class Watch extends React.Component { render () { return{this.props.hours}:{this.props.minutes}}}// Equivalent functional componentconst Watch = (props) =>{props.hours}:{props.minutes};
Both snippets define the same Watch
component. Yet, the second is way shorter and even drops this
to access the props in the JSX template.
这两个片段定义了相同的Watch
组件。 然而,第二个是短的方式,甚至降到this
来访问模板JSX道具。
Every component must expose a unique root element as a template. To adhere to this rule, the common fix is to wrap the template in a div
.
每个组件都必须公开一个唯一的根元素作为模板。 为了遵守此规则,常见的解决方法是将模板包装在div
。
React 16 brings us a new feature called . Now you can replace those useless div
s with React.Fragment
s.
React 16为我们带来了一个名为的新功能。 现在,您可以将那些无用的div
替换为React.Fragment
。
The output template will be the fragment content without any wrapper.
输出模板将是没有任何包装的片段内容。
const Login = () =>;const Login = () =>;const Login = () => // Short-hand syntax <>;
As soon as your React app is dynamic, you have to deal with components’ states.
一旦您的React应用程序是动态的,您就必须处理组件的状态。
Using states seems pretty straightforward. Initialize the state content in the constructor
and then call setState
to update the state.
使用状态似乎非常简单。 在constructor
初始化状态内容,然后调用setState
更新状态。
For some reason, you may need to use the current state or props values when calling setState
to set the next state’s value.
由于某些原因,在调用setState
设置下一个状态的值时,可能需要使用当前状态或props值。
// Very bad pratice: do not use this.state and this.props in setState !this.setState({ answered: !this.state.answered, answer });// With quite big states: the tempatation becomes bigger // Here keep the current state and add answer propertythis.setState({ ...this.state, answer });
The issue is that React doesn’t ensure this.state
and this.props
have the value you’re expecting. setState
is asynchronous, because state updates are batch to optimize DOM manipulations (see the details in the and this ).
问题在于,React无法确保this.state
和this.props
具有您所期望的值。 setState
是异步的,因为状态更新是批处理的,可以优化DOM操作(请参见和的详细信息)。
// Note the () notation around the object which makes the JS engine// evaluate as an expression and not as the arrow function blockthis.setState((prevState, props) => ({ ...prevState, answer }));
To prevent corrupted states, you must use setState
with the function parameter. It provides proper state and props values.
为了防止损坏状态,必须将setState
与function参数一起使用。 它提供适当的状态和道具值。
There are many ways to bind an element’s events to its component, and some are not recommended.
有多种方法可以将元素的事件绑定到其组件,但不建议使用某些方法。
The first and legitimate solution appears in the :
第一个合法的解决方案出现在 :
class DatePicker extends React.Component { handleDateSelected({target}){ // Do stuff } render() { return } }
It might disappoint you when you find out that it doesn’t work.
当您发现它不起作用时,它可能会让您感到失望。
The reason is that when using JSX, this
value is not bound to the component instance. Here are three alternatives to make it work:
原因是使用JSX时, this
值未绑定到组件实例。 以下是三种使其可行的选择:
// #1: use an arrow function this.handleDateSelected(event)}/>// OR #2: bind this to the function in component constructorconstructor () { this.handleDateSelected = this.handleDateSelected.bind(this); }// OR #3: declare the function as a class field (arrow function syntax)handleDateSelected = ({target}) => { // Do stuff}
Using an arrow function in JSX as in the first example seems appealing at first. But don’t do it. In reality, your arrow function will be and it’ll hurt performance.
首先,像在第一个示例中那样在JSX中使用箭头函数似乎很有吸引力。 但是不要这样做。 实际上,将箭头函数,这会影响性能。
Also, be careful about the last solution. It uses class fields syntax which is only a .
另外,请注意最后的解决方案。 它使用类字段语法,这只是的 。
This means that you have to use to the code. If the syntax is not finally adopted, your code will break.
这意味着您必须使用来代码。 如果最终没有采用语法,则代码将中断。
Last but not the least, the container design pattern. This allows you to follow the principle in the React component.
最后但并非最不重要的是容器设计模式。 这使您可以遵循React组件原则。
export class DatePicker extends React.Component { state = { currentDate: null }; handleDateSelected = ({target}) => this.setState({ currentDate: target.value }); render = () => }
A single component handles template rendering and user actions in the same place. Let’s use two components instead:
单个组件可在同一位置处理模板渲染和用户操作。 让我们使用两个组件代替:
const DatePicker = (props) => export class DatePickerController extends React.Component { // ... No changes except render function ... render = () =>;}
Here is the trick. DatePickerContainer
handles user interactions and API calls if necessary. Then it renders a DatePicker
and supplies props.
这是窍门。 DatePickerContainer
在必要时处理用户交互和API调用。 然后,它渲染一个DatePicker
并提供道具。
Thanks to this pattern, the container component replaces the presentational component. This functional component becomes useless without props.
由于这种模式,容器组件取代了展示组件。 没有道具,此功能组件将变得无用。
export const DatePickerContainer = connect(mapStateToProps, mapDispatchToProps)(DatePickerController);
In addition, if you use Redux as the state manager for you app, it also plugs well with this pattern.
此外,如果您将Redux用作应用程序的状态管理器,那么它也可以很好地插入此模式。
The connect
function injects props into the component. In our case, it will feed the controller which will forward those props to the component.
connect
函数将props注入到组件中。 在我们的例子中,它将提供给控制器,控制器会将这些道具转发到组件。
Thus both components will be able to access to Redux data. Here is the full code for the container design pattern (without Redux or class fields syntax).
因此,这两个组件都将能够访问Redux数据。 这是容器设计模式的完整代码(没有Redux或类字段语法)。
While writing my learning project for React, I noticed a bad pattern that bothered me with props. On each page, I had a main component that used the store and rendered some nested dumb components.
在为React写我的学习项目时,我注意到一个糟糕的模式使我困扰于道具。 在每个页面上,我都有一个使用商店的主要组件,并呈现了一些嵌套的哑组件。
How can deeply nested dumb components access the main component data ? Actually, they can’t — but you can fix it by:
深度嵌套的哑组件如何访问主组件数据? 实际上,它们不能-但是您可以通过以下方法解决此问题:
The second solution implies that components between the top component and the dumb component will have to pass down props they don’t need.
第二种解决方案意味着顶级组件和哑组件之间的组件将必须传递不需要的道具。
const Page = props =>; const UserDetails = props => ;const inputStyle = { height: '30px', width: '200px', fontSize: '19px', border: 'none', borderBottom: '1px solid black'};const CustomInput = props => // v Finally use fullName value from Page component ; User details
// <= No need fullName but pass it down
The React community has named this issue prop drilling.
React社区已将此问题命名为prop drill 。
Page
is the main component that loads the user details. It is necessary to pass this data through UserDetails
to take it to CustomInput
.
Page
是加载用户详细信息的主要组件。 必须通过UserDetails
传递此数据,以将其传递给CustomInput
。
In this example, the prop only passes through one component which doesn’t need it. But it can be far more if you have reusable components. For example, the Facebook codebase contains a few thousand reusable components!
在此示例中,道具仅穿过一个不需要的组件。 但是,如果您具有可重用的组件,则可能会更多。 例如,Facebook代码库包含数千个可重用组件!
Don’t worry, I’m going to teach you three ways to fix it. The two first methods appear in the : children prop and render prop.
不用担心,我将教您三种修复方法。 前两种方法出现在 : children prop和render prop 。
// #1: Use children propconst UserDetailsWithChildren = props =>;// #2: Render prop patternconst UserDetailsWithRenderProp = props => User details (with children)
{props.children /* <= use children */};const Page = () => User details (with render prop)
{props.renderFullName() /* <= use passed render function */}{/* #1: Children prop */} ;{/* #2: Render prop pattern */} {/* Remember: passing arrow functions is a bad pratice, make it a method of Page class instead */} {/* Defines props.children */} }/>
These solutions are pretty similar. I prefer using children, because it works well within the render method. Note that you can also extend those patterns by providing deeper nested components.
这些解决方案非常相似。 我更喜欢使用子级,因为它在render方法中效果很好。 请注意,您还可以通过提供更深层的嵌套组件来扩展这些模式。
const Page = () =>
The third example uses the experimental context API.
第三个示例使用实验上下文API。
const UserFullNameContext = React.createContext('userFullName');const Page = () =>{/* Fill context with value */} ;const UserDetailsWithContext = () => // No props to provide; User details (with context)
{/* Get context value */} { fullName => }
I don’t recommend this method, because it’s using an experimental feature. (And this is why the API recently .) Also, it forces you to create a global variable to store the context, and your component gets an unclear new dependency (the context can contain anything).
我不推荐这种方法,因为它使用的是实验功能。 (这就是API最近原因。)此外,它迫使您创建一个全局变量来存储上下文,并且您的组件会获得不清楚的新依赖关系(上下文可以包含任何内容)。
Thanks for reading. I hope you learned some interesting tips about React!
谢谢阅读。 希望您了解了一些关于React的有趣提示!
If you found this article useful, please click on the 👏 button a few times to make others find the article and to show your support! 👊
如果您觉得这篇文章很有用,请单击 几次make按钮,以使其他人找到该文章并表示支持! 👊
Don’t forget to follow me to get notified of my upcoming articles 🙏
不要忘记关注我,以获取有关我即将发表的文章的通知 🙏
This is part of my “React for beginners” series on introducing React, its core features and best practices to follow.
这是我的“初学者React”系列的一部分,该系列介绍了React,其核心功能和可遵循的最佳实践。
|
|
?
?
翻译自:
初学react实现路由跳转
转载地址:http://pdwzd.baihongyu.com/