Open source is not easy, thank you for your support, ❤ star concent^_^
Preamble
**[Concent Express]** is a series of articles to help beginners get started concent
quickly, and learn and understand concent state management ideas without obstacles.
Although it is easier to understand after reading this article after learning and using state management libraries such as redux
and , but users who have not used any state management library can also get started very quickly , and the real 0 obstacle to learn to use it and connect to your in react app.mbox
concent
Note that 0 obstacles are emphasized above , including two aspects of learning to use and accessing applications. In order to achieve this purpose, the api must be simple enough. How simple is it? It is so simple that it is react
100% consistent, so that novices do not need to understand additional overviews, and can access state management in the way of writing react components, but it also retains a more advanced abstract interface, so that veterans can follow redux
the pattern to organize the code.
Come on, show it! The key APIs explained in this issue include three top-level APIs run
, useConcent
, , register
and an instance context API setState
. If you learn to use these four APIs, you will already use Concent as your state management solution.
Hello world
All frameworks will use Hello world
as a guide, and we are no exception here to see how simple the concent
version is.Hello world
run defines the module
Like redux, concent has a single global state tree, which is an ordinary json object, but the first-level key is planned as a module name to help users divide the state into multiple modules according to business scenarios, which is convenient for separate management.
Here we need to use run
the interface to start concent and load the module configuration, configure a hello
module named, and define the state for it
import { run } from 'concent';
run({
hello: {
state: { greeting: 'Hello world' },
},
});
register register class component
After the module is defined, our component needs to consume the state of the module. For class components, you register
can use it
import { register } from 'concent';
@register('hello')
class HelloCls extends React.Component{
state = { greeting: '' };
changeGreeting = (e)=> this.setState({greeting: e.target.value})
render(){
return <input value={this.state.greeting} onChange={this.changeGreeting} />
}
}
The appeal code uses the register
interface to HelloCls
register the component as a hello
module. Concent will this
inject an instance context into the current component ctx
for reading data and calling the modification method. At the same time, it also silently replaces the state
sum on this, so that the setState
user can 0 change the code of the original component. , register
you can access state management by just decorating the class component. This is the basis for learning to use and access the react application with zero obstacles . For beginners, if you can write a react component, you will already use concentrate, without any Additional study costs.
this.state === this.ctx.state; // true
this.setState === this.ctx.setState; // true
In the above code, a class member variable is also declared state
equal to { greeting: '' }
, because it greeting
has the same name as the module state, so its value will be replaced by the module before the first rendering Hello world
. In fact, this class member variable can not be declared here state
, write It's just to ensure that removing register
the decorator the component will work without getting an undefined
initial greeting
value.
useConcent to register function components
Using the useConcent
interface to register the module to which the current component belongs useConcent
will return the instance context object ctx
of the current component, which is equivalent to the above class component this.ctx
, we only need to deconstruct it to take out the state
sum setState
.
import { useConcent } from 'concent';
function HelloFn(){
const { state, setState } = useConcent('hello');
const changeGreeting = (e)=> setState({greeting: e.target.value})
return <input value={state.greeting} onChange={changeGreeting} />
}
render component
Finally, let's take a look at the complete code. We found that the top-level Provider
component wraps the root component, because the concent does not rely on React Context api
the implementation of state management, but maintains an independent global context independently, so you connect it in the existing project. Incorporation into the concent is very easy, plug and play, without any additional modification.
Since HelloCls
both and HelloFn
components belong to hello
modules, any instance of them modifies the state of the module, and concentrate will store it in the store and synchronize it to other hello
instances that belong to the same module. State sharing is as simple as that.
import ReactDOM from 'react-dom';
import { run } from 'concent';
import { register, useConcent } from 'concent';
run({/** 略 */});
@register('hello')
class HelloCls extends React.Component{/** 略 */}
function HelloFn(){/** 略 */}
const App = ()=>(
<div>
<HelloCls />
<HelloFn />
</div>
);
ReactDOM.render(App, document.getElementById('root'));
Click me to view the source code
Dependency collection
Whether it is a class component or a function component, the obtained state
object has been converted into a Proxy
proxy object, which is responsible for collecting the data dependencies of the current rendering. Therefore, if it is a conditional read state, it is recommended to use the delayed destructuring method, so that every rendering Lock down the smallest dependency list, reduce redundant rendering, and get better performance.
function HelloFn(){
const { state, setState, syncBool } = useConcent({module:'hello', state:{show:true}});
const changeGreeting = (e)=> setState({greeting: e.target.value});
// 当show为true时,当前实例的依赖是['greeting'],其他任意地方修改了greeting值都会触发当前实例重渲染
// 当show为false时,当前实例无依赖,其他任意地方修改了greeting值不会影响当前实例重渲染
return (
<>
{state.show?<input value={state.greeting} onChange={changeGreeting} />:'no input'}
<button onClick={syncBool('show')}>toggle show</button>
</>
);
}
Consume module state across multiple modules
When a component needs to consume data from multiple modules, connect
parameters can be used to declare multiple modules to connect to.
Use the connect parameter to connect multiple modules
As shown in the following example, connect the two modules bar and baz to ctx.connectedState
obtain the status of the target module:
@register({connect:['bar', 'baz']})
class extends React.Component{
render(){
const { bar, baz } = this.ctx.connectedState;
}
}
connectedState
There is still a dependency collection behavior from the obtained module state, so if there is a conditional rendering statement, the delayed destructuring method is recommended.
Use setModuleState to modify the state
ctx.setModuleState
Modify the target module state by calling the instance context api
changeName = e=> this.ctx.setModuleState('bar', {name: e.target.value})
Epilogue
This article only demonstrates the most basic api usage to help you get started quickly. If you are already an old driver, especially vue3 one piece
at this juncture when the official release has been announced, if you are very disdainful of such clumsy code organization, temporarily Don't rush to deny it first, and open the official website to see other features, there must be highlights you like, including composition api tailored for react , module-level reducer
, computed
, watch
, lifecycle
and other new features. arrive.
Concent carries a complete set of solutions to support the progressive development of react components, that is, without interfering with the development philosophy and component form of react itself, and at the same time, it can obtain huge performance benefits, which means that we can develop bottom-up incremental Iteration, division of state modules, management of derived data, classification of event models, and separation of business codes can be gradually outlined and stripped out in the development process. For development, all domain models and business modules are abstracted clearly at the beginning, and at the same time, they can be adjusted very quickly and flexibly in the iterative process and affect the entire project structure.