silent-auction-rn | A Silent Auction app built with React Native | State Container library
kandi X-RAY | silent-auction-rn Summary
Support
Quality
Security
License
Reuse
Currently covering the most popular Java, JavaScript and Python libraries. See a Sample Here
silent-auction-rn Key Features
silent-auction-rn Examples and Code Snippets
Trending Discussions on State Container
Trending Discussions on State Container
QUESTION
So at work we have this awesome state container hook we built to use in our React application and associated packages. First a little background on this hook and what I'd like to preserve before getting to what I want to do with it. Here's the working code. You'll notice it's commented for easy copy and paste to create new ones.
// Set this accordingly.
const hookName = "MyState";
// Default state values. Make sure your values have explicit types set.
const initialState = {
nums: [] as Number[]
};
// Available actions and the data they require. Specify "null" if action requires no data.
type Actions = {
RESET_NUMS: null,
ADD_NUM: Number,
SET_NUMS: Number[]
};
// Action handler methods. There must be a handler for each action listed above.
const actionHandlers: ActionHandlers = {
RESET_NUMS: () => ({ nums: [] }),
ADD_NUM: ({ nums }, num) => {
nums.push(num);
return { nums };
},
SET_NUMS: ({}, nums) => ({ nums })
};
// Rename these exports accordingly.
export const MyStateProvider = Provider;
export const useMyState = useContextState;
/**************************************************
* *
* You do not need to modify anything below this. *
* *
**************************************************/
/* Context Hook Boilerplate */
import React, { useReducer, useContext, ReactNode } from "react";
import _cloneDeep from "lodash/cloneDeep";
const Context = React.createContext<
{
state: State;
dispatch: Dispatch
} | undefined
>(undefined);
function reducer(state: State, action: Action): State {
const stateClone = _cloneDeep(state);
const newState = actionHandlers[action.type](stateClone, action.data as any);
if (!newState) return state;
return { ...stateClone, ...newState };
}
function Provider({children, defaultState}: {children: ReactNode, defaultState?: State}) {
const [state, reducerDispatch] = useReducer(reducer, defaultState ?? initialState);
const dispatch: Dispatch = (type, data) => reducerDispatch({type, data} as Action);
return (
{children}
);
}
function useContextState() {
const context = useContext(Context);
if (context === undefined) {
throw new Error(`use${hookName} must be used within a ${hookName}Provider`);
}
return context;
}
/* TypeScript Boilerplate */
type Dispatch = (type: T, ...data: (D extends null ? [] : [D])) => void
type State = typeof initialState;
type ActionsMap = {
[K in keyof Actions]: Actions[K] extends null ? { type: K, data?: undefined } : { type: K, data: Actions[K] }
};
type Action = ActionsMap[keyof Actions];
type ActionHandlers = {
[K in keyof Actions]: Actions[K] extends null ? (state: State) => Partial | void : (state: State, data: Actions[K]) => Partial | void;
};
What's cool about it is that the state and dispatch functions are very rigidly typed.
- The type of
initialState
is inferred from its structure so when copying this code to make a new state container hook you don't have to write aState
type and then also a default state object. - The
Actions
type defines actions that are available to be dispatched and the type of each key is the type that is used to enforce the second argument to our dispatch function. - The
actionHandlers
object must have a handler for each action defined onActions
and the handler functions have to conform exactly, receiving the state object as the first argument, and the second argument being a data object that matches the relevant type value onActions
. - The
dispatch
function that consumers of this hook use is almost impossible to misuse. The first argument only accepts valid actions fromActions
keys and the second argument is either not allowed in the case of theActions
type beingnull
or is forced to conform to theActions
type specified.
Here's a typescript playground if you wanna mess with it (go to line 65 to tinker with making dispatch
calls)
Okay so what you might notice is that the bottom half of the code snippet is boilerplate. Well we use these hooks a lot so we are copying and pasting them into various modules in our project. It works great but it's not very DRY and any change to the boilerplate obviously has to be propagated to every single hook. Tedious.
I want to modularize the boilerplate bit but as I start trying to think about it my mind gets boggled about how to maintain the rigid type structures behind the scenes. Here's a brainstorm of what it might be like to consume such a module:
import StateContainer from "@company/react-state-container";
const myState = new StateContainer("MyState");
myState.defaultState({
nums: [] as number[]
});
myState.actionHandler(
"RESET_NUMS",
() => ({ nums: [] })
);
myState.actionHandler(
"ADD_NUM",
({ nums }, num: number) => ({ nums: [...nums, num] })
);
myState.actionHandler(
"SET_NUMS",
({}, nums: number[]) => ({ nums })
);
const {
Provider: MyStateProvider,
useStateContainer: useMyState
} = myState;
export { MyStateProvider, useMyState };
This is just the first thing that came to my head as far as an API goes. Maybe you can think of something better. While consuming the API makes sense to me, how to write this module is where I'm tripping over myself. For one example: How can I infer the type of the default state like I do in the original code? I can write the defaultState
class method using generics but then how do I propagate that generic type into the rest of the class outside of that one method? Is that even possible?
Another question I had pretty quickly. Should I expect the user to provide user-defined types, like for Actions
? Should the consumer have to pass in TypeScript stuff at all or is there a way I can just have them pass only the imperative code and then I can layer on some type magic for those who are taking advantage of TypeScript?
The more I start trying to modularize that code the more I feel like I'm just taking the wrong approach altogether or maybe what I want to do is a fool's errand in the first place.
PS - I know I know, Redux. Sadly I don't get to decide.
ANSWER
Answered 2021-Sep-19 at 05:05PS - I know I know, Redux. Sadly I don't get to decide.
Yes, you're basically re-creating Redux here. More specifically, you're trying to re-create the createSlice
functionality of Redux Toolkit. You want to define a mapping of action names to what the action does, and then have the reducer get created automatically. So we can use that prior art to get an idea of how this might work.
Your current brainstorm involves calling functions on the StateContainer
object after it has been created. Those functions need to change the types of the StateContainer
. This is doable, but it's easier to create the object in one go with all of the information up front.
Let's think about what information needs to be provided and what information needs to be returned.
We need a name
, an initialState
, and a bunch of actions
:
type Config = {
name: string;
initialState: S;
actionHandlers: AH;
}
The type of the state and the type of the actions are generics where S
represents State
and AH
represents ActionHandlers
. I'm using letters to make it clear what's a generic and what's an actual type.
We want to put some sort of constraint on the actions. It should be an object whose keys are strings (the action names) and whose values are functions. Those functions take the state and a payload (which will have a different type for each action) and return a new state. Actually your code says that we return Partial | void
. I'm not sure what that void
accomplishes? But we get this:
type GenericActionHandler = (state: S, payload: P) => Partial | void;
type Config>> = {
...
Our utility is going to take that Config
and return a Provider
and a hook with properties state
and dispatch
. It's the dispatch
that requires us to do the fancy TypeScript inference in order to get the correct types for the type
and data
arguments. FYI, having those as two separate arguments does make is slightly harder to ensure that you've got a matching pair.
The typing is similar to the "TypeScript Boilerplate" that you had before. The main difference is that we are working backwards from ActionHandlers
to Actions
. The nested ternary here handles the situation where there is no second argument.
type Actions = {
[K in keyof AH]: AH[K] extends GenericActionHandler
? (unknown extends P ? never : P )
: never;
};
type TypePayloadPair = {
[K in keyof AH]: Actions[K] extends null | undefined
? [K]
: [K, Actions[K]];
}[keyof AH];
type Dispatch = (...args: TypePayloadPair) => void;
So now, finally, we know the return type of the StateContainer
object. Given a state type S
and an action handlers object AH
, the container type is:
type StateContainer = {
Provider: React.FC<{defaultState?: S}>;
useContextState: () => {
state: S;
dispatch: Dispatch;
}
}
We'll use that as the return type for the factory function, which I am calling createStateContainer
. The argument type is the Config
that we wrote earlier.
The conversion of type
and data
to {type, data} as Action
is not really necessary because the React useReducer
hook doesn't make any requirements about the action type. You can avoid all as
assertions within your function if you pass along the pair of arguments from dispatch
as-is.
export default function createStateContainer<
S,
AH extends Record>
>({
name,
initialState,
actionHandlers,
}: Config): StateContainer {
const Context = React.createContext<
{
state: S;
dispatch: Dispatch
} | undefined
>(undefined);
function reducer(state: S, [type, payload]: TypePayloadPair): S {
const stateClone = _cloneDeep(state);
const newState = actionHandlers[type](stateClone, payload);
if (!newState) return state;
return { ...stateClone, ...newState };
}
function Provider({children, defaultState}: {children?: ReactNode, defaultState?: S}) {
const [state, reducerDispatch] = useReducer(reducer, defaultState ?? initialState);
const dispatch: Dispatch = (...args) => reducerDispatch(args);
return (
{children}
);
}
function useContextState() {
const context = useContext(Context);
if (context === undefined) {
throw new Error(`use${name} must be used within a ${name}Provider`);
}
return context;
}
return {
Provider,
useContextState
}
}
Creating an instance has gotten much, much simpler:
import createStateContainer from "./StateContainer";
export const {
Provider: MyStateProvider,
useContextState: useMyState
} = createStateContainer({
name: "MyState",
initialState: {
nums: [] as number[]
},
actionHandlers: {
RESET_NUMS: () => ({ nums: [] }),
ADD_NUM: ({ nums }, num: number) => {
nums.push(num);
return { nums };
},
SET_NUMS: ({}, nums: number[]) => ({ nums })
}
});
QUESTION
I want to call a method from a child Component and I have this code
AppState:
public class AppState
{
public string MyMessage { get; private set; }
public string MyMsgToChildren { get; private set; }
public event Action OnChange;
public void SetMessage(string msg)
{
MyMessage = msg;
NotifyStateChanged();
}
public void SetMessageToChildren(string msg)
{
MyMsgToChildren = msg;
NotifyStateChanged();
}
private void NotifyStateChanged() => OnChange?.Invoke();
}
and Child Component #1:
@inject AppState AppState
============================
#1 Child
send from Father :@AppState?.MyMsgToChildren
Send To Parent
============================
@code {
protected override void OnInitialized()
{
AppState.OnChange += StateHasChanged;
}
public void Dispose()
{
AppState.OnChange -= StateHasChanged;
}
void SetMessage()
{
AppState.SetMessage("Message From Child #1");
}
}
and the #2 Child is the same code with #1 and I have a parent component :
@page "/State"
@inject AppState AppState
============================
Parent
send from child:@AppState?.MyMessage
Send To Parent
@code {
public string MsgToChildren { get; private set; } = "Hi, Im your father - ";
int i = 0;
protected override void OnInitialized()
{
AppState.OnChange += StateHasChanged;
}
public void Dispose()
{
AppState.OnChange -= StateHasChanged;
}
void SendMsgTochildren()
{
i++;
AppState.SetMessageToChildren(MsgToChildren + i.ToString());
}
/* I want to call this method from Child*/
void TargetMethod(int page)
{
}
}
this app works well and just I want to call this method: "TargetMethod(int page)" from one of my child components and I need to pass an integer parameter as well
I want to use this code for pagination. I try to make a component(pagination) and add it to each table component and the pagination will be the grandchild of the main component and I know I can use the other ways but I prefer to use state Container to communicate between pagination and others
ANSWER
Answered 2021-Sep-08 at 16:04I want to call this method: "TargetMethod(int page)" from one of my child components and I need to pass an integer parameter as well
then you can try like this:
AppState.cs
public class AppState
{
public Action OnCounterChanged { get; set; }
}
Grandparent.razor
@inject AppState AppState;
@page "/grandparent"
Counter Value from Grandparent : @Counter
@code{
public int Counter { get; set; }
protected override void OnInitialized()
{
AppState.OnCounterChanged += OnCounterChanged;
}
private void OnCounterChanged(int counter)
{
Counter = counter;
StateHasChanged();
}
}
Parent.razor
@inject AppState AppState;
Counter Value from Parent : @Counter
@code{
public int Counter { get; set; }
protected override void OnInitialized()
{
AppState.OnCounterChanged += OnCounterChanged;
}
private void OnCounterChanged(int counter)
{
Counter = counter;
StateHasChanged();
}
}
Child.razor
@inject AppState AppState;
Counter Value from child : @Counter
Update Counter
@code{
public int Counter { get; set; }
private void UpdateCounter()
{
AppState.OnCounterChanged.Invoke(++Counter);
}
}
I'm updating the counter from the child component and invoking the event with an int
parameter. (it's just a demo)
QUESTION
I've been trying to implement a custom keyboard solution for one of my projects, so I created a custom component for this. Each time a key is pressed on this component, a javascript function is called and receives the id of the input that has currently the focus.
function WriteInput(elementId, letter) {
var myElement = document.getElementById(elementId);
myElement.value = letter.toLowerCase();
myElement.dispatchEvent(new Event('change'));
return true;
}
The jsInterop :
public async Task WriteInput(string elementId, string letter)
{
return await _js.InvokeAsync("WriteInput", elementId, letter);
}
The KeyBoard Component logic (Keyboard.Id is a value retrieved from a state container) :
private async void OnClick(string letter)
{
await _FocusService.WriteInput(KeyBoard.Id, letter);
}
The html :
The issue here is that I can see the letters in the input, but the ViewModel.Username is not updated even if the change event is thrown, what am I missing here, I have the same code as in here and apparently it is working : Changing an Input value in Blazor by javascript doesn't change it's binded property value
Thanks for your help
ANSWER
Answered 2021-Aug-30 at 10:07I've taken the code you provided down to a bare bones working model that shows the bind value being updated. The JS is in site.js which is referenced in _Host.cshtml.
@page "/"
SoftKeyboard
First Name:
Surname:
UserName:
Focus Control:
First Name
Surname
User Name
A
S
D
F
K
First Name: @_model.FirstName
Surname: @_model.Surname
User Name: @_model.UserName
@code {
[Inject] IJSRuntime _js { get; set; }
async void SoftClick(char key)
{
await _js.InvokeAsync("WriteInput", selectedField, key);
}
void FieldSelector(ChangeEventArgs e)
{
selectedField = e.Value.ToString();
}
private string selectedField = "FirstNameField";
public class Model
{
public string UserName { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
}
Model _model = new Model();
}
QUESTION
In my Blazor server app, I have a page called Home that is basically a search page. On the Home page (the "parent") there is a form with controls to filter the data stored in a backend database. Each row of the search results has an Edit button that displays a bootstrap dialog allowing one to edit the data. After the Save button on the UpdateDocumentNumber (grandchild) component is clicked I want to refresh the search results in the Home page (parent).
- Parent: Home (page) with search results grid; embeds a DisplayDocumentNumber component for each item
- Child: DisplayDocumentNumber component, which has its own (child) UpdateDocumentNumber component
- Grandchild: UpdateDocumentNumber component - bootstrap dialog
My understanding is I can use Event Callback to do this; however, while I can raise/invoke the Event Callback from grandchild to child, I cannot seem to then inform the parent from the child.
Some more details...
As the Home ("parent" page) iterates over the returned list of items it inserts a component (the "child"), and then the
component has a component to reference the Edit dialog. Here's the Home page iterating over the search results:
@foreach (var documentNumber in DocumentNumbers)
{
// DocumentNumber parameter in DisplayDocumentNumber receives the data from the documentNumber local var
}
Here's the DisplayDocumentNumber component:
public partial class DisplayDocumentNumber : ComponentBase
{
[Parameter]
public DocumentNumberDto DocumentNumber { get; set; }
[Parameter]
public EventCallback OnDocumentNumberUpdatedEventCallback { get; set; }
}
Note the public EventCallback OnDocumentNumberUpdatedEventCallback { get; set; }
. This works properly from grandchild to child.
Inside the DisplayDocumentNumber.razor component is the row that gets rendered for each document number in the search results, including an Edit button that has a DOM event to show the bootstrap dialog. And, finally, as mentioned above, there is the component I.e.
@DocumentNumber.Column1Name
@DocumentNumber.Column2Name
...etc
Edit
If Event Callbacks only work from a grandchild to child or child to parent, do I have to create some kind of state container as described by Chris Sainty (https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/)? Or, am I missing something about Event Callbacks? I've tried to eliminate the child component, but failed because the Edit button always showed the last item iterated in the grid.
ANSWER
Answered 2021-Jul-10 at 22:14I can think of a few options. One is to give the grandchild access to the main page. This does not require an event at all:
Parent.razor
Body of page, somewhere in there including
@code{
async Task DoSomething(){
}
}
Grandchild.razor
@code {
[CascadingParameter]
public Parent MainPage {get; set;} // Or whatever your main page is called
async Task StartSomething (){
if (MainPage is not null) MainPage.DoSomething();
}
}
QUESTION
Solved - Solution by @Henk Holterman
By making the method async and adding a Task.Delay into the method, you can execute both by calling the second method from the first after the delay.
private async Task ProcessSelection(SetCardUiModel setCard)
{
numberOfSelected += _uiHelperService.ProcessCardSelection(setCard);
if (numberOfSelected == 3)
{
var setSubmission = uniqueCardCombinations.Where(card => card.BackGroundColor == "yellow").ToList();
var potentialSet = _mapper.Map, List>(setSubmission);
var isSet = _cardHelperService.VerifySet(potentialSet);
_uiHelperService.ChangeSetBackgroundColorOnSubmissionOutcome(setSubmission, isSet);
await Task.Delay(1000);
ProcessSetReplacement();
};
}
Background
I have created the card game called SET in Blazor WASM. In this game you click 3 cards and this can result in either a succesful SET, or a false submission. It works well and now I want to add an additional functionality to signal the outcome of the submission.
Desired result
First method: Upon clicking the 3rd card, the 3 cards should get a green (correct) or red (false) background and after x amount of time (say 1 second) a second method should fire.
Second method: If set was correct, replace the 3 cards with 3 new ones. If set was false, reset background color to white and reset border color to black.
Actual current result
What currently happens is that the result of the first method (green/red background) doesn't show, because there is only one callbackevent. So it does get executed, but it won't become visible until the second method is also executed, by which time either the cards have been replaced, or the backgroundcolor/bordercolor have been reset.
Tried so far
I tried to separate the two methods within the @onclick event, but there is still only one eventcallback and I could not find another way to do this so far, nor on stack overflow.
@onclick="() => { ProcessSelection(uniqueCardCombinations[index]); ProcessSetReplacement(); }
The most notable difference is that EventCallback is a single-cast event handler, whereas .NET events are multi-cast. Blazor EventCallback is meant to be assigned a single value and can only call back a single method. https://blazor-university.com/components/component-events/
I also tried the "State Container" as described here by Chris Sainty, but that only re-renders it and I couldn't adjust it to my situation (not sure that's even possible tbh): https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/
Code
I do intend to clean up the code once I get it working, making it more descriptive and splitting up the ProcessSetReplacement a bit more, but wanted to make it work first.
If you need more background/code info either let me know or you can find the entire repository here: https://github.com/John-Experimental/GamesInBlazor/tree/21_AddSetValidationVisualisation
SetPage.razor:
@for (int i = 0; i < numberOfCardsVisible; i++)
{
var index = i;
@for (int j = 0; j < uniqueCardCombinations[i].Count; j++)
{
}
}
Relevant parts of SetPage.razor.cs (code behind)
private void ProcessSelection(SetCardUiModel setCard)
{
numberOfSelected += _uiHelperService.ProcessCardSelection(setCard);
if (numberOfSelected == 3)
{
var setSubmission = uniqueCardCombinations.Where(card => card.BackGroundColor == "yellow").ToList();
var potentialSet = _mapper.Map, List>(setSubmission);
var isSet = _cardHelperService.VerifySet(potentialSet);
_uiHelperService.SignalSetSubmissionOutcome(setSubmission, isSet);
};
}
private void ProcessSetReplacement()
{
// If it wasn't a set submission, you do nothing
if (numberOfSelected == 3)
{
var redBorderedCards = uniqueCardCombinations.Where(card => card.BorderColor == "red").ToList();
var countGreenBorders = uniqueCardCombinations.Count(card => card.BorderColor == "green");
// The while ensures that the 'ProcessSelection' function, which is also called, has run first
while (redBorderedCards.Count == 0 && countGreenBorders == 0)
{
Thread.Sleep(125);
redBorderedCards = uniqueCardCombinations.Where(card => card.BorderColor == "red").ToList();
countGreenBorders = uniqueCardCombinations.Count(card => card.BorderColor == "green");
}
// Wait 1.5 seconds so that the user can see the set outcome from 'ProcessSelection' before removing it
Thread.Sleep(1500);
if (countGreenBorders == 3)
{
// Replace the set by removing the set submission entirely from the list
uniqueCardCombinations.RemoveAll(card => card.BackGroundColor == "yellow");
numberOfSelected = 0;
// Check if the field currently shows more cards than normal (can happen if there was no set previously)
// If there are more cards, then remove 3 cards again to bring it back down to 'normal'
numberOfCardsVisible -= numberOfCardsVisible > settings.numberOfCardsVisible ? 3 : 0;
EnsureSetExistsOnField();
}
else
{
foreach (var card in redBorderedCards)
{
card.BackGroundColor = "white";
card.BorderColor = "black";
}
}
};
}
ANSWER
Answered 2021-Mar-15 at 21:02Do not call both methods in onclick
.
- Call
ProcessSelection
, process result and set red/green there. - Call
StateHasChanged()
- Set timer to one second in
ProcessSelection
. Use Timer fromSystem.Timers
. - On Elapsed of the timer call
ProcessSetReplacement
.
QUESTION
I am building a simple React-native app with Expo for rating Github repositories and ran into a nasty issue. When I am trying to render a list of the repositories with Flatlist it throws me the following error: undefined is not an object (evaluating 'repository.fullName'); although my code is pretty much identical to the one in React-native docs. Here is the RepositoryList.jsx where the Flatlist is being rendered:
import React from 'react';
import { FlatList, View, StyleSheet } from 'react-native';
import RepositoryItem from './RepositoryItem'
const styles = StyleSheet.create({
separator: {
height: 10,
},
});
const repositories = [
{
id: 'rails.rails',
fullName: 'rails/rails',
description: 'Ruby on Rails',
language: 'Ruby',
forksCount: 18349,
stargazersCount: 45377,
ratingAverage: 100,
reviewCount: 2,
ownerAvatarUrl: 'https://avatars1.githubusercontent.com/u/4223?v=4',
},
{
id: 'reduxjs.redux',
fullName: 'reduxjs/redux',
description: 'Predictable state container for JavaScript apps',
language: 'TypeScript',
forksCount: 13902,
stargazersCount: 52869,
ratingAverage: 0,
reviewCount: 0,
ownerAvatarUrl: 'https://avatars3.githubusercontent.com/u/13142323?v=4',
}
];
const ItemSeparator = () => ;
const RepositoryList = () => {
return (
}
/>
);
};
export default RepositoryList
and RepositoryItem.jsx which should be rendered within the Flatlist:
import React from 'react'
import {View, Text, StyleSheet} from 'react-native'
const RepositoryItem = ({repository}) => {
return(
Full name:{repository.fullName}
Description:{repository.description}
Language:{repository.language}
Stars:{repository.stargazersCount}
Forks:{repository.forksCount}
Reviews:{repository.reviewCount}
Rating:{repository.ratingAverage}
)
}
styles = StyleSheet.create({
item: {
marginHorizontal: 16,
backgroundColor: 'darkorange'
},
});
export default RepositoryItem
After doing my research I found that a lot of people have run into this issue too, and apparently it persists since 0.59 (my React-native is on 0.62, Windows). Apparently the error is being cause by a babel module '@babel/plugin-proposal-class-properties' and the solution would be deleting this module from .babelrc, according to this Github thread https://github.com/facebook/react-native/issues/24421. The problem is that my babel.config.js is extremely simple, and I don't see how I can exclude this module from being required for babel to work. My babel.config.js:
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
};
};
Perhaps there is a way to exclude it through tweaking babel in node_modules, but this solution seems unlikely. Any help or suggestions regarding this issue will be greatly appreciated!
ANSWER
Answered 2021-Jan-13 at 17:23I think your problem consists in destructuring repository
in your renderItem
method of the FlatList
. You cannot just destructure whatever you want, you have to destructure item
from the Flatlist.
Try this way:
const RepositoryList = () => {
return (
}
/>
);
};
Or, if you really want to
const RepositoryList = () => {
return (
}
/>
);
};
QUESTION
As everyone knows, we can use docker start [dockerID]
to start a closed container.
But, If this container exits immediately after startup. What should I do?
For example, I have a MySQL container, it runs without any problems. But the system is down. At next time I start this container. It tell me a file is worry so that this container immediately exit.
Now I want to delete this file, but this container can not be activated, so I can't enter this container to delete this file. What should I do?
And if I want to open bash in this state container, What should I do?
ANSWER
Answered 2020-Oct-29 at 01:31Delete the container and launch a new one.
docker rm dockerID
docker run --name dockerID ... mysql:5.7
Containers are generally treated as disposable; there are times you're required to delete and recreate a container (to change some networking or environment options; to upgrade to a newer version of the underlying image). The flip side of this is that containers' state is generally stored outside the container filesystem itself (you probably have a docker run -v
or Docker Compose volumes:
option) so it will survive deleting and recreating the container. I almost never use docker start
.
Creating a new container gets you around the limitations of docker start
:
If the container exits immediately but you don't know why,
docker run
ordocker-compose up
it without the-d
option, so it prints its logs to the consoleIf you want to run a different command (like an interactive shell) as the main container command, you can do it the same as any other container,
docker run --rm -it -v ...:/var/lib/mysql/data mysql:5.6 sh
docker-compose run db sh
If the actual problem can be fixed with an environment variable or other setting, you can add that to the startup-time configuration, since you're already recreating the container
QUESTION
Im currently using redux to manage my state. The scenario is as such , Upon successful creation of a new object , i would like to append the response data into my existing state container as i don't wish to make a new API call to render it.
initial State:const initialState = {
workflowobject:{},
};
SAGA:export function* workerCreateTransitionApproval(action) {
const data = yield call(() => axiosInstance.post(`/transition-approval-meta/create/`, action.data))
yield put({ type: "STORE_WORKFLOW_DATA", payload: data.data.data, fetch: 'workflowobject' , label: 'transition_approvals'})
}
So over here , i upon recieving the "signal" so to speak to create a transition approval , i will catch that event and create make an axios post request to my backend , which will then return a response of the transition_approval
. I will then store this transition_approval
as the payload which i will use later on.
const loadWorkflowObject = (state, action) => {
return updateObject(state, {
workflowobject: { ...state.workflowobject, [action.label]: action.payload }
})
}
const storeData = (state, action) => {
switch (action.fetch) {
case 'workflowobject': return loadWorkflowObject(state, action)
}
}
const reducer = (state = initialState, action) => {
switch (action.type) {
case 'STORE_WORKFLOW_DATA': return storeData(state, action);
case 'CLEAR_CLASS_STATES': return clearClassStates(state, action);
case 'CLEAR_OBJECT_STATES': return clearObjectStates(state, action);
default:
return state;
}
}
export default reducer;
So in my reducer , it will first go into the case STORE_WORKFLOW_DATA
which will then return the reducer function loadWorkflowObject
. This is where i wish to 'append' the data back to the state tree.
The tricky part here is that im using this loadWorkflowObject
reducer for fetching data too , and im already using the spread operator here.
The code that i have shown above will override my preexisting data that i have in the transition_approvals
object , if possible , i would like to append the data in instead.
ANSWER
Answered 2020-Jun-09 at 15:12you can do this:
const loadWorkflowObject = (state, action) => {
return updateObject(state, {
workflowobject: { ...state.workflowobject, [action.label]: state. transition_approvals.concat(action.payload) }
})
}
QUESTION
I write a server-side blazor app. You can create sensors with states (Good, warning, error...) with a little API for reporting new states.
Now I want to refetch the new state (or all sensors) on a blazor client from the DB if the API gets called.
I tried to apply "3. State Container" from this guide: https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/
How I can force the site to refetch the sensors after a API request? The Sensor and Blazor Client are different devices.
@inject ISensorData _db
Dashboard
@if (sensors is null)
{
Laden...
}
else
{
if (sensors.Count == 0)
{
Keine Sensoren vorhanden!
}
else
{
foreach (SensorModel sensor in sensors)
{
@sensor.Name @sensor.Message
}
}
}
@code {
private List sensors;
protected override async Task OnInitializedAsync()
{
sensors = await _db.GetSensors();
}
private string StatusColor(int status)
{
switch (status)
{
case 0:
return "btn-secondary";
case 1:
return "btn-success";
case 2:
return "btn-warning";
case 3:
return "btn-danger";
default:
return "btn-secondary";
}
}
}
My API
[HttpGet("updateState")]
public async Task UpdateState(int id, int status, string? message)
{
if (id <= 0)
{
return BadRequest();
}
if (string.IsNullOrEmpty(message))
{
message = "";
}
try
{
await _db.UpdateState(id, status, message);
//Task.Run(async () => { _dbState.CallRequestRefresh(); });
_dbState.CallRequestRefresh();
}
catch(Exception ex)
{
throw ex;
}
return NoContent();
} enter code here
My API Controller
{
_db = db;
NavigationManager = navigationManager;
hubConnection = new HubConnectionBuilder()
.WithUrl("https://localhost:44346/dbRefreshHub")
.Build();
hubConnection.StartAsync();
}
ANSWER
Answered 2020-May-26 at 10:28I do not entirely understand your question as it is not clearly put, and I may be missing something...
However, the State Container pattern proposed by you can't serve you in any way. It is intended to manage state for your components, etc. But I believe that you are looking for a way to notify your client side app that the "API gets called", and that it ( the client side app ) should update the new state... Am I right ?
If yes, then, I believe you can implement the SignalR Client (Microsoft.AspNetCore.SignalR.Client) to do that.
A while ago, I saw in one of the Blazor previews by Daniel Roths, some code snippet demonstrating how to use SignalR Client in Blazor. Search for it, or perhaps look up the topic in the docs, and see if it can offer you some remedies.
Hope this works...
QUESTION
I have a number of medical pictures presented on canvas, as an example below.
I’m trying to make a tool that allows you to select any area of the image with the tool in the form of an expandable circle, and fill in only that part of it that doesn't go beyond the outline in which the original click pixel was located. A filled outline is drawn on a separate canvas layer.
Now I use the most common iterative stack implementation of flood fill with variable tolerance (comparison function). You can familiarize yourself with it here. Everything doesn't work very well, especially in pictures where there are no strong contrast differences and in high-resolution images, everything else is pretty slow.
I had the idea to create a state container and look for whether the desired filled outline exists there and if so, then just replace the canvas pixel array (though, again, I will have to resort to some additional processing, the canvas pixel array contains 4 channel, while at the output of the algorithm only 1 is obtained and just replacing the content doesn't work, you need to replace each pixel with a pixel divided into 4 channels) instead of a slow flood fill each time. But this approach has one significant problem: memory consumption. As you might guess, a filled outline, especially of a decent resolution alone, can take up quite a lot of space, and their set becomes a real problem of memory consumption.
It was decided to store the finished contours in the form of polygons and extracting them from the container simply fill them with faster context fill. The algorithm used allows me to output a set of boundaries, but due to the features of the algorithm, this array is unordered and connecting the vertices in this order, we get only a partially filled outline (right picture). Is there a way to sort them in such a way that I could only connect them and get a closed path (the holes that are in the filled outline in the left picture shouldn't be a priori, so we don’t have to worry about them)?
Summing up, due to the not-so-best fill job, I think to use a different algorithm / implementation, but I don’t know which one. Here are some of my ideas:
Use a different implementation, for example, a line scanning method. As far as I know, here is one of the fastest and most effective implementations of the algorithm among open sources. Pros: possible efficiency and speed. Cons: I need to somehow convert the result to a polygon, rewrite the algorithm to javascript (probably emscripten, can do it well, but in any case I will have to rewrite a considerable part of the code).
Use a completely different approach.
a) I don’t know, but maybe the Canny detector can be useful for extracting the polygon. But as far as the use of the program is meant on the client side, it will be unprofitable to extract all the boundaries, it is necessary to figure out how to process only the necessary section, and not the entire picture.
b) Then, knowing the border, use any sufficiently fast fill algorithm that simply won't go beyond the boundaries found.
I'll be glad to know about some other ways, and even better to see ready-made implementations in javascript
UPD:
For a better understanding, the tool cursor and the expected result of the algorithm are presented below.
ANSWER
Answered 2020-May-09 at 16:19Here is an example with opencv
Below should work or eventually use the fiddle link provided inside the code snippet
Of interest: approxPolyDP which may be sufficient for your needs (check Ramer-Douglas-Peucker algorithm)
// USE FIDDLE
// https://jsfiddle.net/c7xrq1uy/
async function loadSomeImage() {
const ctx = document.querySelector('#imageSrc').getContext('2d')
ctx.fillStyle = 'black'
const img = new Image()
img.crossOrigin = ''
img.src = 'https://cors-anywhere.herokuapp.com/https://i.stack.imgur.com/aiZ7z.png'
img.onload = () => {
const imgwidth = img.offsetWidth
const imgheight = img.offsetHeight
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, 400, 400)
}
}
function plotPoints(canvas, points, color = 'green', hold = false){
const ctx = canvas.getContext('2d')
!hold && ctx.clearRect(0, 0, 400, 400)
ctx.strokeStyle = color
Object.values(points).forEach(ps => {
ctx.beginPath()
ctx.moveTo(ps[0].x, ps[0].y)
ps.slice(1).forEach(({ x, y }) => ctx.lineTo(x,y))
ctx.closePath()
ctx.stroke()
})
}
const binarize = (src, threshold) => {
cv.cvtColor(src, src, cv.COLOR_RGB2GRAY, 0)
const dst = new cv.Mat()
src.convertTo(dst, cv.CV_8U)
cv.threshold(src, dst, threshold, 255, cv.THRESH_BINARY_INV)
cv.imshow('binary', dst)
return dst
}
const flip = src => {
const dst = new cv.Mat()
cv.threshold(src, dst, 128, 255, cv.THRESH_BINARY_INV)
cv.imshow('flip', dst)
return dst
}
const dilate = (src) => {
const dst = new cv.Mat()
let M = cv.Mat.ones(3, 3, cv.CV_8U)
let anchor = new cv.Point(-1, -1)
cv.dilate(src, dst, M, anchor, 1, cv.BORDER_CONSTANT, cv.morphologyDefaultBorderValue())
M.delete()
cv.imshow('dilate', dst)
return dst
}
const PARAMS = {
threshold: 102,
anchor: { x: 180, y: 180 },
eps: 1e-2
}
const dumpParams = ({ threshold, anchor, eps }) => {
document.querySelector('#params').innerHTML = `thres=${threshold} (x,y)=(${anchor.x}, ${anchor.y}) eps:${eps}`
}
document.querySelector('input[type=range]').onmouseup = e => {
PARAMS.threshold = Math.round(parseInt(e.target.value, 10) / 100 * 255)
dumpParams(PARAMS)
runCv(PARAMS)
}
document.querySelector('input[type=value]').onchange = e => {
PARAMS.eps = parseFloat(e.target.value)
dumpParams(PARAMS)
runCv(PARAMS)
}
document.querySelector('#imageSrc').onclick = e => {
const rect = e.target.getBoundingClientRect()
PARAMS.anchor = {
x: e.clientX - rect.left,
y: e.clientY - rect.top
}
dumpParams(PARAMS)
runCv(PARAMS)
}
const contourToPoints = cnt => {
const arr = []
for (let j = 0; j < cnt.data32S.length; j += 2){
let p = {}
p.x = cnt.data32S[j]
p.y = cnt.data32S[j+1]
arr.push(p)
}
return arr
}
loadSomeImage()
dumpParams(PARAMS)
let CVREADY
const cvReady = new Promise((resolve, reject) => CVREADY = resolve)
const runCv = async ({ threshold, anchor, eps }) => {
await cvReady
const canvasFinal = document.querySelector('#final')
const mat = cv.imread(document.querySelector('#imageSrc'))
const binaryImg = binarize(mat, threshold, 'binary')
const blurredImg = dilate(binaryImg)
const flipImg = flip(blurredImg)
var contours = new cv.MatVector()
const hierarchy = new cv.Mat
cv.findContours(flipImg, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
const points = {}
let matchingPoints = null
let matchingContour = null
for (let i = 0; i < contours.size(); ++i) {
let minArea = 1e40
const ci = contours.get(i)
points[i] = contourToPoints(ci)
if (anchor) {
const point = new cv.Point(anchor.x, anchor.y)
const inside = cv.pointPolygonTest(ci, point, false) >= 1
const area = cv.contourArea(ci)
if (inside && area < minArea) {
matchingPoints = points[i]
matchingContour = ci
minArea = area
}
}
}
plotPoints(canvasFinal, points)
if (anchor) {
if (matchingPoints) {
plotPoints(canvasFinal, [matchingPoints], 'red', true)
if (eps) {
const epsilon = eps * cv.arcLength(matchingContour, true)
const approx = new cv.Mat()
cv.approxPolyDP(matchingContour, approx, epsilon, true)
const arr = contourToPoints(approx)
console.log('polygon', arr)
plotPoints(canvasFinal, [arr], 'blue', true)
}
}
}
mat.delete()
contours.delete()
hierarchy.delete()
binaryImg.delete()
blurredImg.delete()
flipImg.delete()
}
function onOpenCvReady() {
cv['onRuntimeInitialized'] = () => {console.log('cvready'); CVREADY(); runCv(PARAMS)}
}
// just so we can load async script
var script = document.createElement('script');
script.onload = onOpenCvReady
script.src = 'https://docs.opencv.org/master/opencv.js';
document.head.appendChild(script)
canvas{border: 1px solid black;}
.debug{width: 200px; height: 200px;}
binarization threeshold
eps(approxPolyDp)
params:
ps: polygon is output in the console
implem with maskedit: in below snippet I had more fun and implemented the mask. We may make the snippet [full page] then hover over the first canvas.
// USE FIDDLE
// https://jsfiddle.net/c7xrq1uy/
async function loadSomeImage() {
const ctx = document.querySelector('#imageSrc').getContext('2d')
ctx.fillStyle = 'black'
const img = new Image()
img.crossOrigin = ''
img.src = 'https://cors-anywhere.herokuapp.com/https://i.stack.imgur.com/aiZ7z.png'
img.onload = () => {
const imgwidth = img.offsetWidth
const imgheight = img.offsetHeight
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, 400, 400)
}
}
function plotPoints(canvas, points, color = 'green', hold = false){
const ctx = canvas.getContext('2d')
!hold && ctx.clearRect(0, 0, 400, 400)
ctx.strokeStyle = color
Object.values(points).forEach(ps => {
ctx.beginPath()
ctx.moveTo(ps[0].x, ps[0].y)
ps.slice(1).forEach(({ x, y }) => ctx.lineTo(x,y))
ctx.closePath()
ctx.stroke()
})
}
const binarize = (src, threshold) => {
cv.cvtColor(src, src, cv.COLOR_RGB2GRAY, 0)
const dst = new cv.Mat()
src.convertTo(dst, cv.CV_8U)
cv.threshold(src, dst, threshold, 255, cv.THRESH_BINARY_INV)
cv.imshow('binary', dst)
return dst
}
const flip = src => {
const dst = new cv.Mat()
cv.threshold(src, dst, 128, 255, cv.THRESH_BINARY_INV)
cv.imshow('flip', dst)
return dst
}
const dilate = (src) => {
const dst = new cv.Mat()
let M = cv.Mat.ones(3, 3, cv.CV_8U)
let anchor = new cv.Point(-1, -1)
cv.dilate(src, dst, M, anchor, 1, cv.BORDER_CONSTANT, cv.morphologyDefaultBorderValue())
M.delete()
cv.imshow('dilate', dst)
return dst
}
const PARAMS = {
threshold: 102,
anchor: { x: 180, y: 180 },
eps: 1e-2,
radius: 50
}
const dumpParams = ({ threshold, anchor, eps }) => {
document.querySelector('#params').innerHTML = `thres=${threshold} (x,y)=(${anchor.x}, ${anchor.y}) eps:${eps}`
}
document.querySelector('input[type=range]').onmouseup = e => {
PARAMS.threshold = Math.round(parseInt(e.target.value, 10) / 100 * 255)
dumpParams(PARAMS)
runCv(PARAMS)
}
document.querySelector('input[type=value]').onchange = e => {
PARAMS.eps = parseFloat(e.target.value)
dumpParams(PARAMS)
runCv(PARAMS)
}
document.querySelector('#imageSrc').onclick = e => {
const rect = e.target.getBoundingClientRect()
PARAMS.anchor = {
x: e.clientX - rect.left,
y: e.clientY - rect.top
}
dumpParams(PARAMS)
runCv(PARAMS)
}
// sorry for the globals, keep code simple
let DST = null
let MATCHING_CONTOUR = null
let DEBOUNCE = 0
document.querySelector('#imageSrc').onmousemove = e => {
if (Date.now() - DEBOUNCE < 100) return
if (!MATCHING_CONTOUR || !DST) { return }
const rect = e.target.getBoundingClientRect()
DEBOUNCE = Date.now()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
const dst = DST.clone()
plotIntersectingMask(dst, MATCHING_CONTOUR, { anchor: { x, y }, radius: PARAMS.radius })
dst.delete()
}
const contourToPoints = cnt => {
const arr = []
for (let j = 0; j < cnt.data32S.length; j += 2){
let p = {}
p.x = cnt.data32S[j]
p.y = cnt.data32S[j+1]
arr.push(p)
}
return arr
}
const plotIntersectingMask = (dst, cnt, { anchor, radius }) => {
const { width, height } = dst.size()
const contourMask = new cv.Mat.zeros(height, width, dst.type())
const matVec = new cv.MatVector()
matVec.push_back(cnt)
cv.fillPoly(contourMask, matVec, [255, 255, 255, 255])
const userCircle = new cv.Mat.zeros(height, width, dst.type())
cv.circle(userCircle, new cv.Point(anchor.x, anchor.y), radius, [255, 128, 68, 255], -2)
const commonMask = new cv.Mat.zeros(height, width, dst.type())
cv.bitwise_and(contourMask, userCircle, commonMask)
userCircle.copyTo(dst, commonMask)
cv.imshow('final', dst)
commonMask.delete()
matVec.delete()
contourMask.delete()
userCircle.delete()
}
loadSomeImage()
dumpParams(PARAMS)
let CVREADY
const cvReady = new Promise((resolve, reject) => CVREADY = resolve)
const runCv = async ({ threshold, anchor, eps, radius }) => {
await cvReady
const canvasFinal = document.querySelector('#final')
const mat = cv.imread(document.querySelector('#imageSrc'))
const binaryImg = binarize(mat, threshold, 'binary')
const blurredImg = dilate(binaryImg)
const flipImg = flip(blurredImg)
var contours = new cv.MatVector()
const hierarchy = new cv.Mat
cv.findContours(flipImg, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
const points = {}
let matchingPoints = null
let matchingContour = null
for (let i = 0; i < contours.size(); ++i) {
let minArea = 1e40
const ci = contours.get(i)
points[i] = contourToPoints(ci)
if (anchor) {
const point = new cv.Point(anchor.x, anchor.y)
const inside = cv.pointPolygonTest(ci, point, false) >= 1
const area = cv.contourArea(ci)
if (inside && area < minArea) {
matchingPoints = points[i]
matchingContour = ci
minArea = area
}
}
}
plotPoints(canvasFinal, points)
if (anchor) {
if (matchingPoints) {
MATCHING_CONTOUR = matchingContour
plotPoints(canvasFinal, [matchingPoints], 'red', true)
if (eps) {
const epsilon = eps * cv.arcLength(matchingContour, true)
const approx = new cv.Mat()
cv.approxPolyDP(matchingContour, approx, epsilon, true)
const arr = contourToPoints(approx)
//console.log('polygon', arr)
plotPoints(canvasFinal, [arr], 'blue', true)
if (DST) DST.delete()
DST = cv.imread(document.querySelector('#final'))
}
}
}
mat.delete()
contours.delete()
hierarchy.delete()
binaryImg.delete()
blurredImg.delete()
flipImg.delete()
}
function onOpenCvReady() {
cv['onRuntimeInitialized'] = () => {console.log('cvready'); CVREADY(); runCv(PARAMS)}
}
// just so we can load async script
var script = document.createElement('script');
script.onload = onOpenCvReady
script.src = 'https://docs.opencv.org/master/opencv.js';
document.head.appendChild(script)
canvas{border: 1px solid black;}
.debug{width: 200px; height: 200px;}
#imageSrc{cursor: pointer;}
binarization threeshold
eps(approxPolyDp)
params:
Community Discussions, Code Snippets contain sources that include Stack Exchange Network
Vulnerabilities
No vulnerabilities reported
Install silent-auction-rn
Support
Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from over 650 million Knowledge Items
Find more librariesExplore Kits - Develop, implement, customize Projects, Custom Functions and Applications with kandi kits
Save this library and start creating your kit
Share this Page