Motty
原生桌面 SSH 工作台:终端、SFTP/SCP、端口转发、VNC 与 RDP 远程桌面、AI 助手都在一个窗口里。Go 编写,没有 Electron,空闲时保持安静。免费开源,支持 macOS、Windows 和 Linux。
Translation pending
React state management, built for AI coding agents. Your agent writes structured, testable code, and a linter checks its work. You can still read every line.
Developer toolsTypeScript · GherkinGitHub @marcglasbergOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Powerful State Management for React and React Native. Docs: https://kissforreact.org
Loading the full README.
Read the full README ↗Kiss helps AI agents stay on track, session after session, while spending fewer tokens.
npm install kiss-for-react
The store holds all application state. Here are a few examples:
// Your state is a number
const store = createStore<number>({initialState: 1});
// Your state is a plain JavaScript object
const store = createStore({initialState: {name: 'Mary', age: 25}});
// Your state is an instance of an ES6 class
class State { constructor(public name: string, public age: number){} }
const store = createStore<State>({initialState: new State('Mary', 25)});
Use a StoreProvider to add the store to your component tree:
function App() {
return (
<StoreProvider store={store}>
<AppContent />
</StoreProvider>
);
};
The useAllState hook lets you access the whole state from any component.
The component re-renders when any part of the state changes (not recommended, but good for
fast prototyping).
function MyComponent() {
const state = useAllState<State>();
return <div>{state.name} is {state.age} years old</div>;
};
The useSelect hook selects only the part of the state that your component needs.
The component re-renders only when that part changes.
function MyComponent() {
const name = useSelect((state: State) => state.name);
const age = useSelect((state: State) => state.age);
return <div>{name} is {age} years old</div>;
};
The useObject hook also causes the component to re-render only when needed:
function MyComponent() {
const state = useObject((state: State) => ({
name: state.name,
age: state.age,
}));
return <div>{state.name} is {state.age} years old</div>;
};
These hooks connect to the store with React's own
useSyncExternalStore,
so React reads the state itself, compares what each component selected, and renders only
the components whose selection changed. React also checks the state again before
committing a
render it paused (a transition), and renders again if the state changed meanwhile, so a
screen never shows parts of two different states at the same time.
An action is a class with its own reducer function. This reducer has access to the current state and returns a new state.
class Increment extends Action {
reduce() {
// The reducer has access to the current state
return this.state + 1; // It returns a new state
};
}
The store's state is immutable.
The only way to change the store's state is by dispatching an action, wich runs the action's reducer to get a new state. The new state replaces the current one, and affected components re-render.
// Dispatch an action
store.dispatch(new Increment());
// Dispatch multiple actions
store.dispatchAll([new Increment(), new LoadText()]);
// Dispatch an action and wait for it to finish
await store.dispatchAndWait(new Increment());
// Dispatch multiple actions and wait for them to finish
await store.dispatchAndWaitAll([new Increment(), new LoadText()]);
// Dispatch an action when the state meets a condition
store.dispatchWhen(new LoadText(), (state) => state.count >= 3);
Hooks for dispatching actions include useDispatch, useDispatchAll, useDispatchWhen,
etc.
function MyComponent() {
const dispatch = useDispatch();
return (
<Button onClick={() => dispatch(new LoadText())}>
Click me!
</Button>
);
};
You can also get the store with useStore and dispatch actions directly:
function MyComponent() {
const store = useStore();
return (
<Button onClick={() => store.dispatch(new LoadText())}>
Click me!
</Button>
);
};
To dispatch actions when the component mounts, when some values change, and when it
unmounts,
use useStoreEffect instead of a useEffect:
useStoreEffect({
deps: userId, // List the dependencies
// Loads information needed for this screen
onMount: (store) => store.dispatch(new LoadUser(userId)),
// When the userId changes, stop listening to the old user and load the new one
onDepsChange: (store, oldUserId) => {
store.dispatch(new StopListening(oldUserId));
store.dispatch(new LoadUser(userId));
},
// When the component unmounts, clean up any resources used by this screen
onUnmount: (store) => store.dispatch(new CleanResources()),
});
To reload the data on screen when the user comes back to the browser tab, or when the
internet
comes back, add onFocus and onOnline (there are also onBlur and onOffline). They
run
only on the transitions, while the component is mounted, never on mount. Give the action a
fresh period to skip the reload when the data is recent:
useStoreEffect({
onMount: (store) => store.dispatch(new LoadPrices()),
onFocus: (store) => store.dispatch(new LoadPrices()),
onOnline: (store) => store.dispatch(new LoadPrices()),
});
Also available in components with useIsFocused() and useIsOnline(),
for an "offline" banner.
Actions can fetch data from the internet or do any other async work.
This is the beginning of the README. Read the rest at the original. Read the full README ↗