I'd like to use composables inside composables, but it turned out, that composables lose reactivity.
Please, give me advice how to tackle this problem.
The desired behavior is beneath:
import {ref, computed} from "vue";
import useFirstStep from "components/draft/use/useFirstStep";
import useSecondStep from "components/draft/use/useSecondStep";
export default function useFifthStep() {
const {isValidFirstStep} = useFirstStep();
const {isValidSecondStep} = useSecondStep();
const isValidStep = computed(() => {
return isValidFirstStep.value &&
isValidSecondStep.value &&
});
return {isValidStep};
}
It's hard to say without seeing the example code from useFirstStep and useSecondStep, but I bet you have a ref inside export, but you should keep it outside, so that whenever you use this composable you would not initialize given ref.
So useFirstStep.js should look like:
const isValidFirstStep = ref(false)
export default function useFirstStep() {
// some logic to set isValidFirstStep
return {isValidFirstStep};
}
Related
My Problem
The nextjs documentation on mdx states that it does not support frontmatter. Instead it is suggested to create a constant and export it [1]. However I can't seem to get at data exported in such a way. For instance using the following
/* -- ./pages/example.mdx -- */
export const meta = {
title: 'some example title'
}
/* -- ./pages/index.js -- */
import Example from './example.mdx';
export default function Index ({ ... props }) {
return <Example />
}
It seems that what gets imported can be used as a react component, but there does not seem to be a reference to the meta property anywhere.
Example does not have a meta property
import { meta } from './example.mdx does not yield anything
There is no meta key on the rendered components
Using require ('./example.mdx') yields the same results.
What I wanted to do
I have a list of markdown files and want to create an overview page that lists all of them, using the metadata defined in every file. Something akin to the following
import fs from 'fs/promises';
import path from 'path';
export async function getStaticProps () {
const root = path.join (process.cwd (), 'pages/items');
const listing = await fs.readdir(root);
const items = listing
.filter (item => item.endsWith ('.mdx'))
.map (item => {
const meta = require (`./items/${item}`).meta;
const id = item.replace (/\.md$/, '');
return { id, ... meta }
});
return { props: { items } };
}
export default function Overview ({ items, ... props }) {
/* ... use items */
}
Edit
It seems like there is a big difference between using .md and .mdx. In the examples I gave here I used .mdx, but locally I had used .md. Switching extensions makes everything work.
It is strange that the extension makes such a difference even though both of them are configured in next.config.js
const withMDX = require ('#next/mdx') ({
extension: /\.mdx?$/
});
module.exports = withMDX ({ /* ... */ });
[1] https://nextjs.org/docs/advanced-features/using-mdx#frontmatter
Use .mdx extension instead of a .md extension.
Seems like you can create a typing file to import it if you are using typescript
Step 1 - Create typing file
declare module '*.mdx' {
export const meta: {
title: string
}
}
Step 2 - import the exported content
import Example, {meta} from './example.mdx';
Got the answer from here https://gist.github.com/peterblazejewicz/1ac0d99094d1886e7c9aee7e4faddef3#file-index-d-ts-L68
Is it ok to have a reducer calling sub-reducers in its default block?
function aReducer(state = {}, action) {
switch(action.type) {
case XYZ:
... // know what to do
default:
// don't know this action, let's delegate to the children
return {
sub1: subReducer1(state.sub1, action),
sub2: subReducer2(state.sub2, action)
}
}
}
Yes, that's absolutely legal and reasonable to do.
You might want to read through the Redux docs section on "Structuring Reducers" for further ideas on how you can organize reducer logic as well.
You can put all the reducers in a common folder and inside that, you can combine the separate reducers into a single one like the following code.
import { combineReducers } from 'redux'
import Reducer1 from './Reducer1.js'
import Reducer2 from './Reducer2.js'
export default combineReducers( { Reducer1, Reducer2,... } )
and use the following code to use that as a single reducer.
import reducers from '../../reducers'(reducer's root folder name/path)
let store = createStore( reducers );
I have the following reducer:
const selectEntityReducer = function(entityState, action) {
const selectedEntity = entityState.allEntities.filter(e => (e.id == action.id))[0]
const newStateForSelectEntity = updateObject(entityState, {selectedEntity: selectedEntity});
return newStateForSelectEntity;
};
entityState shape looks like {entities:[{id:1}, {id:2}], selectedEntity:{id:2}}.
I have a React component that is connected to the store like this:
function mapStateToProps(state) {
return {
selectEntity: state.entities.selectEntity
};
}
However, it never re-renders.
If I say selectEntities: state.entities in mapStateToProps, then the component re-renders. But I'm only interested in the selected entity for this component.
I'm aware that enforcing immutability down the entire state tree is required for redux to function properly. But I thought that is what I was doing in selectEntityReducer.
Any extra context can be seen in the full redux code in this gist.
Its happens because you filter old piece of state.
You must copy your entities:
const newEntities = entityState.allEntities.slice();
const newSelectedentities = newEntities.filter.........
Copy piece of ctate if it array and then process it.
Basic Problem
I've got a Redux store with the following data:
foo: {
currentId: 1,
things: [{id: 1}, {id: 2}),
}
I'd like to make a utility method somewhere (eg. on a Foo singleton object) such that any module in my code can do:
import Foo from 'foo';
foo.getCurrentFoo(); // returns foo.thins[foo.currentId];
but I'm having trouble figuring out where to put it.
Failed Attempt
My initial attempt was to create a Foo component singleton:
// Foo.js
class FooBase extends React.Component {
getCurrentFoo() {
return this.state.foo.things[this.state.foo.currentId];
}
}
const Foor = connect((state) => state.foo)(FooBase);
export default new FooWrapper();
But that doesn't work. Redux complaieds about the property store not existing (when I did new FooWrapper()). That makes sense, because my component isn't inside a <Provider />. However, I just want a stand-alone utility class/object, not something actually in the DOM, which rules out <Provider/>.
How can I make a method like the one described above, that actually works, without involving <Provider /> ... and where do I put it?
The nice thing about the react-redux helpers is that they allow you to use connect() and <Provider /> to automatically pass the store to child components via React's context. However, that doesn't necessarily mean that you have to use these helpers, especially in areas of a codebase that don't use React.
So here lies the problem: connect() and <Provider /> help us by giving our React components access to a singleton instance of a store, but how can we access this store somewhere where connect() and <Provider /> can't be used?
I think the easiest solution here is to create a singleton class that holds on to the store, so any non-React module can still use the store.
So let's say you're creating your store like this:
init.js
import {createStore} from 'redux';
const initialState = {
currentId: 1,
things: ['foo', 'bar']
};
const reducer = (state = initialState, action) => {
if (action.type === 'SET_CURRENT_ID') {
return Object.assign({}, state, {
currentId: action.id
});
}
return state;
};
const store = createStore(reducer);
This store takes an action of type SET_CURRENT_ID which simply returns a new state with the currentId property changed to whatever was handed to it. You could then get the current "thing" by doing something like store.getState().things[store.getState().currentId]. So let's create a Singleton class that can hold on to the store and provide a wrapper around this functionality.
store.js
class Store {
constructor() {
this._store = undefined;
}
setStore(store) {
this._store = store;
}
getCurrentThing() {
if (this._store) {
const {things, currentId} = this._store.getState();
return things[currentId];
}
}
setCurrentThing(id) {
if (this._store) {
const action = {
type: 'SET_CURRENT_ID',
id
};
this._store.dispatch(action);
}
}
}
export let singletonStore = new Store();
This class creates an instance the first time it is used, and uses that instance every subsequent time. So when you originally create your store, simply import this class and call setStore().
init.js
import {singletonStore} from './store';
singletonStore.setStore(store);
Then, every subsequent file where singletonStore is used will have the same state.
test.js
import {singletonStore} from './store';
console.log(singletonStore.getCurrentThing()); // 'bar'
singletonStore.setCurrentThing(0);
console.log(singletonStore.getCurrentThing()); // 'foo'
This should work just fine for your need to use your store in modules that don't have the benefit of being passed the store magically with connect() and <Provider />.
Is this possible?
I'm using redux store in an IoC environment and want to add middleware to the store after it is created.
e.g.:
class MyApp {
store = createStore(...);
}
let app = new MyApp();
// later on
import thunk from 'redux-thunk';
app.store.addEnhancer(thunk);
I have created a function to do this. If redux think this is valuable, I can do a PR.
This is code that tailored to my module. The actual one add to PR will look a bit different.
addMiddleware(middleware: Middleware) {
const middlewareAPI: MiddlewareAPI<any> = {
getState: this.getState,
dispatch: (action) => this.dispatch(action)
};
this.dispatch = compose(middleware(middlewareAPI))(this.dispatch);
}
I was able to use the code from above from unional but I needed to change it slightly to get it working with 2018 redux.
constructor(myMiddleware: myMiddleware) {
this.addMiddleware(myMiddleware)
}
addMiddleware(middleware: Middleware) {
this.redux.dispatch = compose(applyMiddleware(middleware))(this.redux.dispatch);
}